Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.WaitAll on a list in F#

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.

like image 702
pad Avatar asked Dec 22 '22 17:12

pad


1 Answers

As Robert explains, if you want to call WaitAll, you'll have to cast the elements sequence to the base type Task and then convert it to an array. You can define your extension member for Task to make the tas simpler:

type System.Threading.Tasks.Task with
  static member WaitAll(ts) =
    Task.WaitAll [| for t in ts -> t :> Task |]

I'm using array comprehension and cast instead of Seq.cast because Seq.cast takes untyped IEnumerable - so F# infers better type for the extension method.

Another option is not to call WaitAll at all - if you don't do it, the Result 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 use List.map to collect all results, the behavior would be almost the same.

like image 125
Tomas Petricek Avatar answered Dec 26 '22 00:12

Tomas Petricek