异步方法和异步委托

11

C# 3.0 in a nutshell指出,异步方法异步委托看起来很相似,但行为上却非常不同。

以下是该书对两者的介绍:

异步方法

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

异步委托

  1. 可能会阻塞任意长度的时间。
  2. BeginInvoke方法立即返回给调用者。
  3. 内置的编译器支持。

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

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

  1. 在这种情况下,如何说它们的行为不同?由于它在内部使用委托,因此像上面的比较是如何进行的?
  2. 您认为使用委托的BeginXXX方法是以与调用者并行执行函数的方式工作的正确方法吗?
  3. 实现异步方法的适当方法是什么,同时保持所有优点,例如充分利用CPU?

有什么想法吗?


在codezone4有一个很好的教程。点击这里 - user1236116
2个回答

7
在核心部分,当你使用回调函数调用BeginFoo()时,你可能会看到两种主要的行为。
  1. 在后台线程上启动工作,并且该线程将一直被使用,直到工作完成并调用回调函数(例如,因为工作是同步的)。
  2. 尽管一些工作发生在后台线程上,但该线程不需要一直被使用(例如,因为工作涉及系统IO,可以在IOCompletionPort上安排回调函数)。
当你使用委托时,会出现上述第一种行为。
一些API(具有支持非阻塞IO调用的底层支持)支持第二种行为。
在'Stream'的特定情况下,我不确定,但我猜它是一个抽象基类,所以这仅仅是一个实现了Read同步版本的子类的默认行为。一个“好”的子类会重写BeginRead/EndRead来实现非阻塞实现。
正如你所说,第二种行为的优点是,你可以有100个挂起的IO调用而不消耗100个线程(线程是昂贵的)。

5
  1. 实现可以不同;例如,异步IO调用可以选择使用完成端口以最小化系统成本,同时不做任何事情。
  2. 这当然是一种方式;在.NET 4.0中,您还可以使用BackgroundWorker,ThreadPool.QueueUserWorkItem或Parallel.For(等等)
  3. 实现因情况而异

我认为书中试图强调的是委托始终包括以下模式:

  • 可阻塞的同步调用(Invoke)
  • 应该不会阻塞的异步调用(BeginInvoke),除非线程池饱和

但它不是唯一的模式。此外,更近期的实现(例如Silverlight中的异步IO方法或WebClient中的方法):信号完成时使用事件而不是IAsyncResult。


谢谢回复。你能指向一个有不同异步方法实现的框架类吗? - Navaneeth K N
2
可能类似于 SqlCommand.BeginExecute*HttpWebRequest.BeginGetResponse - Marc Gravell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接