2

我的印象是让!在 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 服务。

4

2 回答 2

7

正如 Richard 所指出的,异步工作流仍然是完全顺序的。我认为任何尝试进行全自动并行化的项目都没有完全成功,因为这样做太难了。

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

  • 基于任务的你可以在后台启动你的三个任务,然后等到它们全部完成(这可能是你所期望的,所以这里是如何明确地编写它):

    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 有一篇文章讨论了基于异步工作流的各种模式,您可以在财务仪表板示例中找到一个全面的示例

于 2010-10-04T12:05:03.313 回答
2

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

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

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

我印象中

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

于 2010-10-04T08:06:45.213 回答