码迷,mamicode.com
首页 > 其他好文 > 详细

13.1.3 理解工作流的运行

时间:2015-02-10 23:15:25      阅读:271      评论:0      收藏:0      [点我收藏+]

标签:异步工作流

13.1.3 理解工作流的运行

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

清单13.3 显式构造异步工作流 (F#)

async.Delay(fun () –>
  let request = HttpWebRequest.Create(url)
  async.Bind(request.AsyncGetResponse(), fun response –>
    async.Using(response, fun response –>
      let stream = response.GetResponseStream()
      async.Using(new StreamReader(stream), fun reader –>
        reader.AsyncReadToEnd() )
    )
  )
)

Delay 成员把函数包装到工作流值中,可以在以后执行。Lambda 函数体作为创建 HTTP 请求的参数值,使用自定义的异步值绑定,把值指定给 resp 符号。编译器把每个 use 绑定转换成对 Using 成员的调用,这是另一个基本操作,可以通过计算表达式生成器可选地提供的。它负责在工作流结束时,释放对象,不管成功,还是有错误。
Delay 成员是计算生成器成员之一,当实现计算表达式时,可以提供。在清单 13.3 中,它以返回异步工作流(类型是 unit ->Async<’a>)的函数为参数,返回工作流的值(Async<’a>),包装了这个函数。由于有了这个基本操作,整个计算包含在一个函数中,在创建 Async<’a> 值时并不执行,这与前一章关于 option<’a> 类型的例子,非常不同。选项表示值,所以,计算表达式立即运行,执行计算,并返回新的选项值,而工作流表示计算。当我们深入了解 Async<’a> 类型之后,其意思就会变得更清晰。
在清单 13.3 中出现的另一个基本操作类型是 Bind 成员。从前一章我们知道,这是所有计算表达式的核心。在异步工作流中,Bind 可以启动操作,而不会阻塞调用者线程。下面汇总了我们使用基本操作,比如 Async.RunSynchronously,执行工作流时发生的步骤:

1、作为参数值给 Delay 基本操作的函数启动执行,同步创建表示对给定URL 的 HTTP 请求的对象。
2、调用 AsyncGetResponse,结果是基本的异步工作流操作,知道如何启动请求,当操作完成时调用指定的函数。
3、我们执行 Bind 成员,第一个参数为第二步中的工作流,另一个参数为函数,参数为 HTTP 响应,函数体为工作流完成时应该执行的操作。这个函数称为连续(continuation),这个术语我们已经看到过(在第十章讨论递归时,我们使用过,是作为累加器参数,为了累加更多的代码,在以后运行)。
4、Bind 成员运行由 AsyncGetResponse 创建的工作流,向它传递指定的连续。基本工作流操作然后调用 .NET 的 BeginGetResponse 方法,指示系统启动下载响应,当操作完成时调用给定连续。在这里,Bind 成员返回,正在执行操作的线程被释放,可以继续做其它工作,或者返回给线程池。
5、当响应准备就绪时,系统将调用连续。工作流使用 EndGetResponse 的 .NET 方法获得响应对象,执行提供给 Bind 成员的连续,表示工作流的其余部分。注意,系统再从线程池取得线程,因此,每次我们使用 let! 基本操作时,工作流的其余部分可能运行在不同的线程上。
关键点是,当我们执行异步工作流时,不需要等待结果;相反,我们把连续作为参数值;当工作流中的相应步骤完成时,这个连续就执行。有关异步工作流,很重要的是,我们不必显式写使用连续的代码,编译器会把 let! 基本操作转换成对 Bind 成员的调用,自动创建连续。

探究一下异步工作流的类型

我们使用异步工作流,可以不必了解所有的详节,而可能对它是如何实现的,会有点兴趣。我们已经知道,异步工作流类似于函数,表示可以在以后执行的计算。在 F# 库中,类型用函数表示。而这个类型有点复杂,最简单的异步计算可以使用下面的代码来表示:

type Async<‘T> = ((‘T -> unit) * (exn -> unit) * (unit -> unit)) –> unit

这是一个函数,有三个参数组成元组,返回 unit 值。这三个参数很重要,因为它们是连续函数,能够在异步工作流完成时调用。第一个参数是成功连续,类型为 ‘T -> unit,表示把工作流的结果作为参数,当工作流完成时,将调用这个连续,然后,它可以运行其他工作流,或者任何其他代码。第二个参数是异常连续,参数为 exn 值,这是 F# 对 .NET Exception 类型的缩写,可以猜到,它是工作流执行失败时使用的操作。第三个函数称为取消连续,工作流被取消时触发。

虽然异步工作流的精确实现细节并不是必需的,但是,能够创建自定义的基本工作流操作,相当于清单 13.3 中使用的 AsyncGetResponse 方法,非常有用。然后,可以使用其余的积木(building blocks),不需要太多的努力就能异步运行自己的代码了。

13.1.3 理解工作流的运行

标签:异步工作流

原文地址:http://blog.csdn.net/hadstj/article/details/43710733

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!