在没有async&;等候

本文关键字:amp 等候 async | 更新日期: 2023-09-27 17:57:59

在我最近的一次采访中,有人问我如何在c#5.0之前的版本中实现异步编程。我使用代表的BeginInvoke()&EndInvoke()方法我们可以异步调用一个方法。但面试官似乎并不高兴。所以,当我在谷歌上搜索它时,有人说它是异步操作,但不是异步方法。有人能解释一下我们是如何在C#5.0版本之前编写异步方法的吗。

在没有async&;等候

异步编程有几种历史方法。

就BCL而言,大多数实例要么遵循异步编程模型(APM),要么遵循基于事件的异步模式(EAP)(APM更常见)。EAP通常在"上下文"中使用SynchronizationContext来自动恢复。APM不会尝试在"上下文"上恢复。

在EAP之前,还有另一种较旧的模式,很少使用,因为它与WinForms和整个Component系统的集成过于紧密。AFAIK,此模式没有名称,但可以通过SynchronizationObject属性来识别,您可以将其设置为ISynchronizeInvoke的实例(通常是WinForms控件)。然后,组件在该ISynchronizeInvoke实例的上下文中引发其事件。BCL中这种模式的例子很少,但也有一些:System.Timers.TimerSystem.IO.FileSystemWatcherSystem.Diagnostics.Process

也可以说任何一种基于事件的系统都是异步的。即使它不遵循EAP或ISynchronizeInvoke模式,任何可以在未来引发事件以通知订阅者的对象都可以被视为异步组件。

您可以将Rx(反应式扩展)视为异步编程的超集。Rx的字面意思是"正确完成事件",因此它也可以用于实现异步组件。

最后,还有老式的回调(即ContinuationPassingStyle-CPS)。多年前,由于正确实现APM或EAP的复杂性,这在至少一个OSS库中变得有些常见。Node.js的官方异步模式是CPS,尽管它们现在正在迅速向async/await发展(官方API仍然是CPS,它们被封装在与await兼容的promise中)。无论如何,在许多年前,有一个.NET OSS库是非常常见的,并且使用了CPS。我的Google Fu让我失望了,但它可能是早期的HTTP客户端?

以下是异步编程的而非示例:

  • Task.Factory.StartNew
  • new Task
  • Delegate.BeginInvoke
  • ThreadPool.QueueUserWorkItem
  • new Thread
  • Task[Ex].Run

以上所有内容都只是安排代码在某个地方运行,无论是否在线程池线程上,因此并不是真正的异步。尽管MSDN文档中描述Delegate.BeginInvoke时有一个相当令人困惑的术语"异步委托",它只描述异步,而不是真异步(这可能是您面试困惑的原因)。

伪异步是指一个线程将操作视为异步操作,但实际上操作只是在另一个线程上同步。有关真正的异步以及为什么它不需要线程的更多信息,请参阅我的博客文章There Is No Thread。

由于C#.NET 4.0版本,TPL(任务并行库)中有Task类。任务是"未来"或也称为"承诺"。

您可以按如下方式使用它们:

Task<int> task = Task.Factory.StartNew(
  //Long Operation
);
  //perform other work
int result = task.Result;

其中

  • task表示异步调用
  • CCD_ 23是对其结果的访问;类似于期货

正如Java的CompletableFuture所知,TPL提供了Task Continuations,您可以在其中定义一个任务,您希望在第一个任务完成后启动该任务。

您可以按如下方式使用它们:

task1.
      ContinueWith(task2).
          ContinueWith(task3);

或者即使是这样的多连续:

Task.Factory.
    ContinueWhenAll(taskArray, continuation);

Task.Factory.
    ContinueWhenAny(taskArray, continuation);

我希望这能帮助你理解。