我有许多要在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
}
答案 0 :(得分:1)
这是一个可能的解决方案:
CIFilter *brightness = [CIFilter filterWithName:@"CIColorControls" keysAndValues: kCIInputImageKey, beginImage, @"inputBrightness", [sender doubleValue], nil];
答案 1 :(得分:1)
使用帮助程序函数对值x
进行“承诺”,对一组值acc
进行“承诺”:
module Async =
let sequence x acc = async {
let! x = x
let! y = acc
return x :: y
}
我们可以将tasks
按照其“锁定ID”异步分组,稍微整理一下结果列表,然后将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])]
全部披露:为了获得这个不错的结果,我不得不执行几次测试。通常数字会有点小。