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

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



假设我们要下载 web 页的内容,以便可以在我们的应用程序中使用。我们可以使用来自 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,与连接服务器;第二,下载该 web 页。两个操作可能会花很长时间,每一个都可能会阻塞活动的线程,从而导致我们的应用程序没有响应。

要解决这个问题,我们可以在单独的线程中进行下载,但是,使用线程昂贵的,所以,这种方法会限制我们可以并行运行的下载的数量。此外,大部分的时间是线程将等待响应,所以,我们会消费线程资源没有好的理由。若要完美地解决问题,我们应使用异步 API,它能够触发请求,并在操作完成时,调用我们提供的回调:



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 函数,这个代码看起来仍然很复杂。我们不必要改变其结构 ;而不是写顺序的代码,我们将写一个嵌套的回调的序列。

前面的代码段还有另外一个问题,BeginReadToEnd 方法在 .NET 框架中并不可用,因此,我们可能必须自己实现异步下载。不幸的是,使用一个简单的顺序代码,这是不可能的,因为我们需要以缓冲的方式下载这个页面。如果我们想要以异步风格写这段代码 (使用嵌套的回调),我们不可能使用任何内置的结构,例如,while 循环。

我们将会看到,异步工作流解决所有遇到的问题,在写下载程序时。这样就能够以平常的顺序方式写代码,使用标准的控制结构,比如递归,或者甚至是 while 循环。代码异步执行,这意味着,工作流等待操作完成,不需要使用专用的线程。在下一节中,我们将学习如何使用 F# 异步工作流,来实现我们刚讨论过的示例。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值