欢迎使用CSDN-markdown编辑器

来源:互联网 发布:js给input的添加属性 编辑:程序博客网 时间:2024/06/16 17:11

13.1.4 创建基本工作流操作

F# PowerPack 库包含许多重要 I/O 操作的异步版本,但是,不可能包括所有。为此,F# 库还提供了构建自己的基本工作流操作的方法。如果操作要运行在工作流内部,使用的标准 .NET 模式,提供 BeginOperation 和 EndOperation 方法,可以使用 Async.FromBeginEnd 方法;如果把这两种方法作为参数,就会返回异步工作流。
还有其他操作,可以执行而不会阻塞线程。例如,我们可能要等待一个特定事件发生,当它触发时,继续执行工作流。清单 13.4 创建一个基本操作,使用计时器,等待一定的时间(毫秒数),然后继续执行工作流。

清单 13.4 执行异步等待 (F# Interacitve)

> module MyAsync =     let Sleep(time) =    [1] <-- 暂停工作流一定的时间       Async.FromContinuations(fun (cont, econt, ccont) –>         let tmr = new System.Timers.Timer(time, AutoReset = false)         tmr.Elapsed.Add(fun _ -> cont())    [2] <-- 重新进行计算         tmr.Start()      );;(...)> Async.RunSynchronously(async {     printfn "Starting..."     do! MyAsync.Sleep(1000.0)    [3] <-- 等待不会阻塞线程     printfn "Finished!"});;Starting...Finished!val it : unit = ()

F# 库中已经有同样的功能了,由 Async.Sleep 实现,我们将在本章后面会用到它,因此,这仅是一个示例而已。当然,我们也可以使用同步版本 Thread.Sleep,会阻塞工作流,这是一个重要区别。在我们的函数创建计时器,把线程返回到 .NET 线程池期间,这个方法会阻塞线程。而使用我们的基本操作时,.NET 运行时可以并行执行工作流,而不受任何限制。
Sleep 函数[1],其参数为想要延迟处理的毫秒数,使用 Async.FromContinuations 方法构建工作流。这个方法非常接近地反映了工作流的内部结构。参数值是 lambda 函数,在工作流启动时执行。Lambda 的参数为有三个连续的元组,第一个函数在操作成功完成时调用,第二个连续在操作触发异常时调用,类似于前面补充材料中声明的 Async<’T> 类型,第三个连续在取消工作流时触发。在 lambda 函数体中,我们创建一个计时器,指定 Elapsed 事件的处理程序,这个处理程序只运行成功连续[2]。
清单 13.4 表明,创建了自己的基本操作以后,使用它的代码非常简单。因为返回 unit 值,我们用 do! 基本操作,而不是 let! [3]。当代码执行时,它构造了有处理程序的计时器,然后启动;当指定的时间过去,系统从线程池取得一个可用的线程,运行事件处理程序,依次执行计算的其余部分(在本示例,输出到屏幕)。

C# 中的异步工作流

简化 C# 中的异步编程,已经有过无数的尝试,但是,仍没有能够像异步工作流语法一样完美的库。从最终用户的角度来看(只是把代码包装在 async 块中),F# 语法是非常简单的,而这在 C# 中是很难实现的。
我们已经看到过,LINQ 查询大体相当于 F# 的计算表达式,所以,你可能会忍不住要实现 Select 和 SelectMany 操作。理论上,使用查询表达式,写出异步操作是有可能的,但是,能够在查询内部使用的语法,是有限制的。值得关注的是,C# 迭代器也可以用于此目的。《在 C# 中使用迭代器的异步编程》一文对这种方法有叙述(在 http://tomasp.net/blog/csharpasync.aspx)。使用这种技术最实用的库是 Jeffrey Richter 的 PowerThreading 库 [Richter,2009年]。
基于 C# 迭代器、最复杂的一个库,是并发性和协调运行库(CCR)[Chrysanthakopoulos 和 Singh,2005年]。这个库是为微软机器人工作室(Microsoft Robotics studio)而开发的一部分,在这里,响应性和异步处理能力,对任何应用程序都是至关重要的。可以在 Jeffery Richter 的文章《并发事务》中找到有关这个库的详细内容[Richter,2006年]。

现在,可以开始把异步工作流用于更具体的目的了。在下一节,我们将会看到由世界银行所提供的数据服务,讨论如何使用异步工作流来调用。

0 0