假设我有这两个功能:
let dowork n =
async {
do printfn "work %d" n
}
let work i = async {
do! Async.Sleep(2000)
printfn "work finished %d" i }
我如何使用Async.Parallel同时运行它们并在继续之前等待两者完成?
答案 0 :(得分:27)
如前所述,您只需将异步函数放入序列中并将其传递给Async.Parallel
。
但是,如果您需要执行返回不同类型结果的不同作业,则可以使用Async.StartChild
:
let fn1 = async {
do! Async.Sleep 1000
printfn "fn1 finished!"
return 5
}
let fn2 = async {
do! Async.Sleep 1500
printfn "fn2 finished!"
return "a string"
}
let fncombined = async {
// start both computations simultaneously
let! fn1 = Async.StartChild fn1
let! fn2 = Async.StartChild fn2
// retrieve results
let! result1 = fn1
let! result2 = fn2
return sprintf "%d, %s" (result1 + 5) (result2.ToUpper())
}
fncombined
|> Async.RunSynchronously
|> printfn "%A"
答案 1 :(得分:13)
Async.Parallel
采用一系列异步。在这种情况下,我将它传递给列表。
[dowork 1; work 2]
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
如果要返回不同类型的数据,请使用Discriminated Union。
type WorkResults =
| DoWork of int
| Work of float32
let dowork n =
async {
do printfn "work %d" n
return DoWork(n)
}
let work i = async {
do! Async.Sleep(2000)
printfn "work finished %d" i
return Work(float32 i / 4.0f)
}
[dowork 1; work 2]
|> Async.Parallel
|> Async.RunSynchronously
|> printf "%A"
输出
work 1
work finished 2
[|DoWork 1; Work 0.5f|]
答案 2 :(得分:0)
当编译时任务数量固定时,我喜欢有这样的辅助函数:
module Async =
let parallel2 a b =
async {
// Start both tasks
let! x = Async.StartChild a
let! y = Async.StartChild b
// Wait for both to finish
let! i = x
let! j = y
// Return both results as a strongly-typed tuple
return i, j
}
这样的用法:
let work1 = async { return 1 }
let work2 = async { return "a" }
let work1And2 =
async {
let! (a, b) = Async.parallel2 work1 work2
printfn "%i %s" a b
}
注意任务的不同类型。这可能非常有用!
我们可以为 Async<Unit>
添加一个额外的帮助器,因为 ()
和 ((), ())
具有相同的语义:
module Async =
// ...
let doParallel2 (a : Async<Unit>) (b : Async<Unit>) =
parallel2 a b
|> Async.Ignore
然后应用于您的场景:
async {
do! Async.doParallel2 (dowork 1) (work 2)
}