异步方法和异步委托

简而言之,C#3.0异步方法异步委托看起来很相似,但行为却截然不同。

这是本书所说的两者。

异步方法

  1. 很少或从不阻止任何线程。
  2. Begin方法可能不会立即返回给调用者。
  3. 一个没有C#语言支持的商定协议。

异步代理

  1. 可以阻止任何时间长度
  2. BeginInvoke立即返回给调用者。
  3. 内置编译器支持。

该书还说, 异步方法的目的是允许许多任务在少数线程上运行; 异步委托的目的是与调用者并行执行任务

当我通过reflection器查看System.IO.Stream类中的BeginRead()方法时,它正在使用委托并在其上调用BeginInvoke 。 因此异步方法在内部使用异步委托。

  1. 在这种情况下,怎么能说他们的行为不同? 既然它在内部使用委托,那么如何进行上述比较呢?
  2. 您是否认为使用委托的BeginXXX方法是与调用者并行执行函数的方法?
  3. 通过保持充分利用CPU等所有优点来实现异步方法的正确方法是什么?

有什么想法吗?

在核心,当您使用回调调用BeginFoo()时,您可能会看到两个主要行为。

  1. 工作在后台线程上启动,该线程将一直使用,直到工作完成并调用回调(例如因为工作是同步的)。
  2. 虽然某些工作在后台线程上发生,但线程不需要在整个时间内使用(例如,因为工作涉及可以在例如IOCompletionPort上调度回调的系统IO)。

当您使用委托时,会发生上述行为#1。

某些API(具有对非阻塞IO调用的底层支持)支持行为#2。

在’Stream’的特定情况下,我不确定,但我的猜测是它是一个抽象基类,所以这只是一个只实现Read同步版本的子类的默认行为。 ‘good’子类将覆盖BeginRead / EndRead以具有非阻塞实现。

正如你所说,#2的优势在于你可以拥有100个待处理的IO调用而不需要消耗100个线程(线程很昂贵)。

  1. 实施可能会有所不同; 例如,异步IO调用可以选择使用完成端口来最小化系统成本而不执行任何操作。
  2. 这当然是一种方式; 你也可以在.NET 4.0中使用BackgroundWorkerThreadPool.QueueUserWorkItemParallel.For (etc)
  3. 每个实施都有所不同

我想这本书试图强调的是代表们总是包含这种模式:

  • 可以阻止的同步调用( Invoke
  • 除非线程池已饱和,否则不应该真正阻塞的异步调用( BeginInvoke

但它不是唯一的模式。 也; 最近(例如,Silverlight或WebClient的异步IO方法):而不是IAsyncResult ,事件用于表示完成。