13.1.1 异步工作流为什么重要?

来源:互联网 发布:体现中国实力的数据 编辑:程序博客网 时间:2024/06/05 11:06

13.1.1 异步工作流为什么重要?

假设我们要下载网页的内容,在应用程序中使用,我们可以使用 System.Net 命名空间下的 WebClient 类,但是不能演示需要解决的运行复杂、长时间操作的问题。因此,我们需要显式创建 HTTP 请求,然后,下载数据:

var req = HttpWebRequest.Create("http://manning.com");var resp = req.GetResponse();            <-- 初始化连接var stream = resp.GetResponseStream();var reader = new StreamReader(stream);   <-- 下载网页var html = reader.ReadToEnd();Console.WriteLine(html);

这段代码能运行,但远不完美。有两个地方执行 HTTP 通讯,一是初始化与服务器的 HTTP 连接;二是下载网页。这两个操作都可能会花很长时间,也都可能会阻塞活动的线程,从而导致应用程序没有响应。
要解决这个问题,可以把下载放在单独的线程中。但是,使用线程的代价昂贵,因此,这种方法会限制能够并行下载的数量;此外,大部分时间这个线程处于等待响应,造成线程资源的浪费。要完美地解决问题,应使用异步编程接口,它能在操作完成时,执行回调,触发请求:

var req = HttpWebRequest.Create("http://manning.com");req.BeginGetResponse(asyncRes1 => {       <-- 开始操作  var resp = req.EndGetResponse(asyncRes1);  var stream = resp.GetResponseStream();  var reader = new StreamReader(stream);  reader.BeginReadToEnd(asyncRes2 => {     <-- 不退出    var html = reader.EndReadToEnd(asyncRes2);    Console.WriteLine(html);  });});

写这种代码是有难度的,尽管我们使用了 C# 3.0 中的 lambda 函数,代码看起来仍然很复杂。我们必须改变代码的结构,用嵌套的回调的序列代替代码序列。
前面的代码段还有另外一个问题,在 .NET 框架中并没有 BeginReadToEnd 方法,因此,还必须自己实现异步下载。不幸的是,不可能使用简单的代码序列来实现,因为我们需要以缓冲的方式下载页面。如果我们用异步方式写这段代码(使用嵌套的回调),就不能使用任何的内置结构,例如,while 循环。
我们将会看到,异步工作流能够解决下载时遇到的所有问题。代码可以用通常的顺序方式,标准的控制结构,比如递归,或者甚至是 while 循环。代码就能异步执行,工作流等待操作完成,而不需要使用专门的线程。在下一节,我们将学习如何使用 F# 异步工作流,来实现刚才讨论的示例。

0 0
原创粉丝点击