22

异步编程模型基于事件的异步模式之间实际上有什么区别?

使用哪种方法以及何时使用?

4

3 回答 3

20

异步编程模型( APM ) 是您看到的模型和BeginMethod(...)配对EndMethod(...)模型。

例如这里是一个Socket使用APM的实现:

 var socket = new Socket(AddressFamily.InterNetwork, 
                        SocketType.Stream, ProtocolType.Tcp);

 // ...

 socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, 
                     SocketFlags.None, ReceiveCallback, null);

 void ReceiveCallback(IAsyncResult result)
 {
   var bytesReceived = socket.EndReceive(result);

   if (bytesReceived > 0) { // Handle received data here. }

   if (socket.Connected)
   {
     // Keep receiving more data...
     socket.BeginReceive(recvBuffer, 0, recvBuffer.Length, 
                         SocketFlags.None, ReceiveCallback, null);
   }
 }

基于事件的异步模式( EAP ) 是您看到的与配对的MethodAsync(...)模型CancelAsync(...)。通常有Completed活动。BackgroundWorker是这种模式的一个很好的例子。

C# 4.5开始,两者都已被使用任务并行库( TPL )的async/await模式所取代。您将看到它们在方法名称后标有标记,并且通常返回一个可等待的或. 如果您能够以 .NET 4.5 为目标,则绝对应该在 APM 或 EAP 设计上使用此模式。Async TaskTask<TResult>

例如,异步压缩(可能很大)文件:

public static async Task CompressFileAsync(string inputFile, string outputFile)
{
  using (var inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read))
  using (var outputStream = File.Create(outputFile))
  using (var deflateStream = new DeflateStream(outputStream, CompressionMode.Compress))
  {
    await inputStream.CopyToAsync(deflateStream);

    deflateStream.Close();
    outputStream.Close();
    inputStream.Close();
  }
}
于 2013-01-14T23:51:16.130 回答
5

从客户端代码 POV:

EAP:您为名称以“Completed”结尾的事件设置事件处理程序,然后调用名称以“Async”结尾的方法。您有时可以调用名称中带有“取消”的方法,这可能会取消它。

APM:您调用名称以“Begin”开头的方法,然后轮询其结果或接收回调,然后调用以“End”开头的方法。

据我所知,APM 是在大多数 BCL IO 类和 WCF 中实现的,主要是较低级别的不可取消操作(如取消你只是忽略结果)。EAP 可以在更高级别的类中找到,即下载文件,其中有多个步骤和某种有意义的取消行为。

因此,如果您需要选择实施哪个(并且您故意将自己限制在这两个范围内),我想这取决于您正在做的事情是否可以取消。

从客户端代码 POV 中,您并不总是可以选择。如果可以的话,最好使用 C# 4.5 任务,它们可以通过包装器与任何较旧的异步机制一起使用。

于 2013-01-14T23:57:51.627 回答
2

MSDN 文章“决定何时实现基于事件的异步模式”给出了全面的答案。

本文的主要思想(以及对您问题的简短回答)听起来像“默认情况下生成基于事件的模式,并可选择生成 IAsyncResult 模式”

于 2014-01-10T08:55:47.153 回答