F# 中列表中的 Task.WaitAll
我正在使用 F# 进行并行编程。对于固定数量的元素,例如 2 个元素 a1、a2 和一个函数 f,我可以执行以下操作:
let t1 = Task.Factory.StartNew(fun () -> f a1)
let t2 = Task.Factory.StartNew(fun () -> f a2)
Task.WaitAll(t1, t2)
t1.Result, t2.Result
我想知道如何对元素列表执行相同操作:
let ts = List.map (fun a -> Task.Factory.StartNew(fun () -> f a))
Task.WaitAll(ts)
List.map (fun (t: Task<_>) -> t.Result) ts
Visual Studio 发现 Task.WaitAll 无法接受任务< T>列表作为其参数。 Task.WaitAll 可以将 Task [] 作为其参数,但这没有意义,因为我需要获取 Result 进行下一次计算。
I am doing parallel programming using F#. With fixed number of elements, for example with 2 elements a1, a2 and a function f, I can do as follows:
let t1 = Task.Factory.StartNew(fun () -> f a1)
let t2 = Task.Factory.StartNew(fun () -> f a2)
Task.WaitAll(t1, t2)
t1.Result, t2.Result
I wonder how I could do the same with a list of elements:
let ts = List.map (fun a -> Task.Factory.StartNew(fun () -> f a))
Task.WaitAll(ts)
List.map (fun (t: Task<_>) -> t.Result) ts
Visual Studio spots that Task.WaitAll couldn't accept Task< T > list as its parameter. Task.WaitAll can have Task [] as its argument but it makes no sense because I need to get Result for next computation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
正如 Robert 所解释的,如果您想调用
WaitAll
,则必须将元素序列转换为基本类型Task
,然后将其转换为数组。您可以为Task
定义扩展成员,以使任务更简单:我使用数组理解和转换而不是
Seq.cast
因为Seq.cast 采用无类型的
IEnumerable
- 因此 F# 为扩展方法推断出更好的类型。另一种选择是根本不调用
WaitAll
- 如果您不这样做,Result
属性将阻塞,直到任务完成。这意味着无论如何您都会阻塞线程(可能会有更多的阻塞,但我不确定它是否对性能影响太大)。如果您使用List.map
收集所有结果,则行为几乎相同。As Robert explains, if you want to call
WaitAll
, you'll have to cast the elements sequence to the base typeTask
and then convert it to an array. You can define your extension member forTask
to make the tas simpler:I'm using array comprehension and cast instead of
Seq.cast
becauseSeq.cast
takes untypedIEnumerable
- so F# infers better type for the extension method.Another option is not to call
WaitAll
at all - if you don't do it, theResult
properties will block until a task completes. This means that you'll block the thread anyway (there may be a bit larger number of blockings, but I'm not sure if it affects performance too much). If you useList.map
to collect all results, the behavior would be almost the same.这是一个不幸的设计。 Task.WaitAll 使用 c# params 关键字允许您指定多个参数并将它们作为方法中的数组。它还使用 C# 的隐式转换,以便您可以为其指定
Task
。在 F# 中,您必须通过显式转换并转换为数组来自行完成此操作:
现在您可以从
ts
获取结果。This is an unfortunate design. Task.WaitAll is using the c# params keyword to allow you to specify several arguments and have them be an array in the method. It also uses C#'s implicit casting so that you can give it
Task<T>
's.In F# you have to do this yourself by casting explicitly and converting to array:
Now you can get the results from
ts
.数组也有映射,所以没有理由不能将任务放入数组中。
或者你可以转换为数组只是为了等待......
Array also has map, so there's no reason you can't put the tasks in an array.
Or you could convert to an array just for the waitall...