让!按顺序执行?

时间:2010-10-04 07:42:27

标签: f# async-workflow

我的印象是让我们!在f#中,智能足以在并行中执行赋值序列。 但是,以下示例显示不同的行为,a,b,c的分配似乎同步执行。

    let sleep sec =
        async
            {
                System.Threading.Thread.Sleep(sec * 1000)
                return sec
            }

    let bar = async 
                {
                    let! a = sleep 1
                    let! b = sleep 3
                    let! c = sleep 3
                    return a+b+c
                }

    let foo = Async.RunSynchronously(bar)
    printfn "%d" foo

这是/应该如何?

如果我想在并行执行a,b,c,我应该使用Async.Parallell ... |> Async.RunSynchronously ...然后呢?

上面的示例是无用的,真正的用例就像查询数据库并同时调用一些Web服务一样。

2 个答案:

答案 0 :(得分:7)

正如理查德指出的那样,异步工作流仍然是完全顺序的。我不认为任何试图进行全自动并行化的项目都是完全成功的,因为这样做太难了。

但是,异步工作流仍然可以使并行化更容易。关键是它们可以在不阻塞线程的情况下进行等待(这对于可伸缩性至关重要),并且它们还支持自动取消和简单的异常处理,使您的生活更轻松。有各种模式允许您在异步工作流中并行化代码。

  • 基于任务你可以在后台启动你的三个任务,然后等到所有这些任务完成(这可能就是你所期待的,所以这里是如何明确写出来的) :

    let bar = async  { 
      let! atask = sleep 1 |> Async.StartChild
      let! btask = sleep 3 |> Async.StartChild
      let! ctask = sleep 3 |> Async.StartChild
      let! a = atask
      let! b = btask
      let! c = ctask
      return a + b + c } 
    
  • 数据并行 - 如果您有多个相同类型的工作流,则可以使用Async.Parallel创建一个并行运行所有工作流的工作流。然后当你使用let!时,它会运行所有三个任务并等待它们完成:

    let bar = async  { 
      let! all = Async.Parallel [ sleep 1; sleep 3; sleep 3 ]
      return all.[0] + all.[1] + all.[2] } 
    

Don Syme有一篇基于异步工作流程讨论various patterns的文章,你可以在financial dashboard sample中找到一个全面的例子

答案 1 :(得分:2)

let!,在async块(或更正确的“计算表达式”)中执行表达式异步,但整个块仍然是线性执行的。这是async计算表达式的好处:通过为您执行连续传递,使一系列依赖异步操作更容易编写。

(其他类型的计算表达式为let!yield!等提供了自己的语义。)

要执行并行/并发执行,您需要单独执行多个async表达式。

  

我的印象是

你误解了(很容易理解)。