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 = newStreamReader(stream);

reader.BeginReadToEnd(asyncRes2=> {    <-- 不退出

var html =reader.EndReadToEnd(asyncRes2);

Console.WriteLine(html);

});

});

要写这种代码,是很难的。虽然我们使用了 C# 3.0 的 lambda 函数,代码看起来仍然很复杂。我们必须改变其结构;不能顺序地写代码,而是用嵌套的回调的序列。

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

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

时间: 2024-11-06 10:10:08

13.1.1 异步工作流为什么重要?的相关文章

13.1.2 异步下载网页

在我们使用异步工作流来抓取网页内容之前,需要引用 FSharp.PowerPack.dll 库,它包含了许多 .NET 方法的异步版本.开发独立的应用程序时,可以使用添加引用命令:在这一章,我们将使用互动开发模式,因此,创建一个新的 F# 脚本文件,使用 #r 指令(清单  13.1). 清单13.1 使用异步工作流写代码 (F# Interactive) > #r "FSharp.PowerPack.dll";; > open System.IO open System.

13.1 异步工作流

有许多地方需要用到异步操作,比如,使用磁盘.调用 web 服务,或者连接到数据库,异步工作流可能显著提高性能.当应用程序执行异步操作时,很难预测操作什么时候完成.如果不能正确处理异步操作,应用程序就会效率低下,甚至可能停止响应. 要使代码能够执行异步操作,不会阻止调用线程,避免出现问题是必要的,但是,使用当前的技术很难实现.在 F# 中,这极大地简化了,是因为有了异步工作流(asynchronous workflows).在讨论如何使用之前,我们先解释一下问题是什么.

13.1.3 理解工作流的运行

从前一章我们知道,用计算表达式写的 F# 代码,会转换成使用基本操作的表达式,由适当计算生成器提供.对于异步工作流来说,let! 结构转换成对 async.Bind 的调用,return 转换成 async.Return:此外,异步工作流自动延迟,因此,计算本身打包装到额外的基本操作中,确保整个代码包含在一个函数中,这个函数在后面工作流启动时执行.清单 13.3 是清单 13.2 工作流转换后的版本. 清单13.3 显式构造异步工作流 (F#) async.Delay(fun () –> let

Dynamic CRM 2013学习笔记(四十一)流程4 - 异步工作流(Workflow)用法图解

在CRM 2013 里,工作流被分成二类:异步工作流和实时工作流.异步工作流依赖一个windows 服务: Microsoft Dynamics CRM Asynchronous Processing Service , 这个服务必须在CRM 服务器上运行,否则异步工作流不会运行.异步工作流有可能不会立即执行,如果想要立即执行的工作流,可以考虑用实时工作流.CRM 里把它当作实体,所以可以在高级查找里查找它,还可以基于它生成报表.下面详细介绍如何使用异步工作流. 为了使用工作流,要注意权限是否打

13.3.3 获取指标

获取有关国家或地区的数据,需要使用世界银行服务的不同函数,函数的路径是 /countries/indicators,可以在 Data Calls 选项卡的 Query Generator(查询生成器)中找到,它能够请求指定国家特定时间段内的有关指标数据.我们不必单独下载每个感兴趣的地区数据,可以一次性地获得所有国家的信息,在内存中进行处理.以这种方式可以下载更多的数据,而请求的数量较少,因为我们不必为每个地区创建请求. 我们按照与以前相同的模式,首先下载部分示例数据,然后,使用我们自己的 XML

13.2.2 从故障中恢复

世界银行服务对每个用户密钥每天请求数量有限制,还限制了请求的频率,因此,如果我们一次运行大量的请求,有可能会出错.解决的方法是捕获异常,稍后重试请求. 清单 13.7 实现的循环,重复执行请求,直到成功,或者尝试 20 次为止.使用异常报告失败,使用 F# 的 try - with 结构捕捉异常. 清单 13.7 重复运行 web 请求 (F# Interactive) > let worldBankDownload(properties) = let url = worldBankUrl(pr

13.3.2 提取地区信息的代码

我们下载函数的结果是字符串,因此,需要将字符串解析为 XML 文档.由于这个操作我们将经常要用,所以,要写一个简单的打包函数,用 worldBankDownload 下载数据,以 XDocument 对象的形式返回结果.下载异步运行,因此,我们使用异步工作流实现这个函数: let worldBankRequest(props) = async { let! text = worldBankDownload(props) return XDocument.Parse(text) } 代码首先使用

第十三章 异步和数据驱动编程

第十三章异步和数据驱动编程 本章介绍 ■异步工作流编程 ■使用 F# Interactive 浏览数据 ■使用度量单位定义类型 ■处理与可视化数据 我们首先引述了一次对比尔 · 盖茨的采访,他谈到他感兴趣的编程任务的类型,并描述了编写应用程序的典型情况: 从 web 获取数据,不只是考虑把它当作文本,而且要引入结构,然后- -,尝试不同的数据表现方式,且以交互的方式.- 写很少的代码,可以有自己专门的算法来处理数据.[2008年,盖茨] 这正好说出了我们在这一章所要做的,我们将会看到,F# 语言

13.6 第十三章小结

本章重点演示了在 F# 中典型的探究式编程(explorative programming)的生命周期:此外,还介绍了在其他开展过程中非常重要的 F# 语言和库功能. 我们首先从网站获取数据.为此,我们使用异步工作流,在标准的 F# 库中用 F# 计算表达式实现.异步工作流能够用于高效执行 I/O 和其他非常耗时的操作,而不会阻塞调用者线程和浪费资源.下载数据以后,就可以使用 LINQ to XML 库研究其结构,然后,进行解析,并把它转换为类型化的 F# 表示形式.所有这一切都使用了交互式风格