我的印象是让我们!在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服务一样。
答案 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
表达式。
我的印象是
你误解了(很容易理解)。