[英]Controlling async actions that might conflict in F#
我要在F#中執行許多操作( Async<T> list
)。 我可以並行執行大多數這些動作,但是由於文件鎖定等原因,有些動作可能會發生沖突。
對於每個動作,我可以生成一個“鍵”( int
),該鍵確定動作是否可能沖突:
a
具有鍵i
,操作b
具有鍵j
並且i = j
,則a
和b
可能會沖突。 它們必須順序執行。 a
具有鍵i
,動作b
具有鍵j
和i <> j
,則a
和b
將永遠不會沖突。 它們可以並行執行。 我想以一種有效的方式執行我的動作(int * Async<T>) list
,並且沒有沖突。
我認為該過程將類似於:
Async
如何在F#中實現呢?
這些問題通常如何處理?
我嘗試完全按順序執行:
let wrapTasks<'T> (tasks : (int * Async<'T>) list) : Async<'T list> = async {
return
tasks
|> Seq.map (fun (k, t) -> t |> Async.RunSynchronously)
|> Seq.toList
}
這是一個可能的解決方案:
let wrapTasks (tasks : (int * Async<'T>) list) =
tasks
|> List.groupBy fst
|> Seq.map (fun (k, ts) -> async {
for (i, t) in ts do
let! r = t
()
})
|> Async.Parallel
|> Async.RunSynchronously
通過一個輔助函數,對值x
取一個“承諾”,對一組值acc
取一個“承諾”:
module Async =
let sequence x acc = async {
let! x = x
let! y = acc
return x :: y
}
我們可以按照tasks
的“鎖ID”對tasks
進行異步分組,對結果列表進行一些清理,然后將每個組sequence
為單個async
,以“包含”該組結果的列表。 然后並行處理此列表。 ts : 'b list []
可用后,我們將其展平:
let wrapTasks tasks = async {
let! ts =
tasks
|> List.groupBy fst
|> List.map (snd >> List.map snd)
|> List.map (fun asyncs -> List.foldBack Async.sequence asyncs (async { return [] }))
|> Async.Parallel
return ts |> List.ofArray |> List.collect id
}
這可以用例如測試
List.init 50 (fun i -> i % 5, async {
let now = System.DateTime.UtcNow.Ticks
do! Async.Sleep 10
return i, now })
|> wrapTasks
|> Async.RunSynchronously
|> List.groupBy snd
|> List.map (fun (t, rs) -> t, rs |> List.map fst)
|> List.sort
通過改變除數,我們可以調整並行度,並使自己確信該函數按預期運行:-)
[(636766393199727614L, [0; 1; 2; 3; 4]); (636766393199962986L, [5; 6; 7; 8; 9]); (636766393200068008L, [10; 11; 12; 13; 14]); (636766393200278385L, [15; 16; 17; 18; 19]); (636766393200382690L, [20; 21; 22; 23; 24]); (636766393200597692L, [25; 26; 27; 28; 29]); (636766393200703235L, [30; 31; 32; 33; 34]); (636766393200918241L, [35; 36; 37; 38; 39]); (636766393201027938L, [40; 41; 42; 43; 44]); (636766393201133307L, [45; 46; 47; 48; 49])]
全面披露:為了獲得這個不錯的結果,我不得不執行了幾次測試。 通常數字會有點小。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.