异步编程 APM 与 EAP 的比较

22

“异步编程模型”(Asynchronous Programming Model)和“基于事件的异步模式”(Event-based Asynchronous Pattern)之间的实际区别是什么?

在何时使用哪种方法?


2
MSDN文档已经很好地涵盖了这个问题。 - Stephen Cleary
很棒的文章!一定会加入我的书签收藏。 - Erik
3个回答

21

异步编程模型 (APM) 是使用 BeginMethod(...)EndMethod(...) 成对出现的模型。

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

 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 开始,这两种模式都已被 async/await 模式所取代,后者使用了 任务并行库TPL)。你会看到它们在方法名后面标记为 Async,通常返回一 个可等待的 TaskTask<TResult>。如果你能够针对 .NET 4.5 进行开发,那么应该优先选择使用这种模式而不是 APM 或 EAP 设计。

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

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();
  }
}

5

从客户端代码的角度来看:

EAP:您为名称以“完成”结尾的事件设置了事件处理程序,然后调用以“Async”结尾的方法。有时,您可以调用名称中包含“Cancel”的方法来取消它。

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

据我所知,这两种方式中,APM已被大多数BCL IO类和WCF实现,主要是较低级别的不可取消操作(要取消操作,您只需忽略结果)。EAP在更高级别的类中发现,即下载文件之类的操作,其中有多个步骤和某种有意义的取消行为。

因此,如果您需要选择要实现哪种方式(并且您故意限制自己只能使用这两种方式),那么我想这取决于您正在执行的操作是否可取消。

从客户端代码的角度来看,您并不总是有选择的余地。最好使用C# 4.5 Tasks,如果可以的话,它们可以通过包装器与任何旧的异步机制一起使用。


2
关于__APM__设计中缺少取消功能的观点很好。 此外,正如提到的那样,Task.Factory.FromAsync(...)是C# 4.5包装器,可将__APM__风格转换为__TPL__模式。 参见:<a href="http://msdn.microsoft.com/en-us/library/dd997423.aspx" title="TPL and Traditional .NET Asynchronous Programming"></a> - Erik
抱歉,在这里与SO评论斗争(为什么他们大多数“支持”的链接格式在评论中不起作用)?TPL和传统的.NET异步编程 - Erik

2

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