[英]F# Is there a Async.Sequential to match Async.Parallel?
[英]F# using Async.Parallel to run 2 tasks in parallel
假設我有這兩個功能:
let dowork n =
async {
do printfn "work %d" n
}
let work i = async {
do! Async.Sleep(2000)
printfn "work finished %d" i }
我將如何使用 Async.Parallel 同時運行它們並等待兩者完成后再繼續?
如前所述,您只需將異步函數放入序列中並將它們傳遞給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"
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|]
當任務數量在編譯時固定時,我喜歡這樣的 helper function:
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)
}
F# 中的新功能是應用程序。 有了這些,我們可以擴展async
計算表達式以支持並行and!
關鍵詞!
這是擴展名:
type AsyncBuilder with
member this.Bind2(a, b, f) =
async {
let! x = Async.StartChild a
let! y = Async.StartChild b
let! i = x
let! j = y
return f (i, j)
}
用法如下:
let work1And2 =
async {
let! a = work1
and! b = work2
printfn "%i %s" a b
}
let makeBoxed (job: Async<'a>) : Async<obj> =
async {
let! result = job
return box result
}
let mixedParallel2 (a: Async<'T1>) (b: Async<'T2>): Async<'T1*'T2> =
async {
let! results = Async.Parallel [| makeBoxed a ; makeBoxed b |]
return (unbox<'T1> results.[0]), (unbox<'T2> results.[1])
}
與其他答案不同,這個答案正確處理異常和取消。 例如,當其中一個異步計算引發異常時,生成的組合計算會立即退出並引發該異常,而不是等待其他計算完成。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.