Task.WaitAll в списке в F#
Я делаю параллельное программирование с использованием 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 не может принять список Task
3 ответа
Как объясняет Роберт, если вы хотите позвонить WaitAll
вам нужно будет привести последовательность элементов к базовому типу Task
а затем преобразовать его в массив. Вы можете определить свой добавочный член для Task
чтобы сделать вкус проще:
type System.Threading.Tasks.Task with
static member WaitAll(ts) =
Task.WaitAll [| for t in ts -> t :> Task |]
Я использую понимание массива и приведение вместо Seq.cast
так как Seq.cast
принимает нетипизированный IEnumerable
- поэтому F# выводит лучший тип для метода расширения.
Другой вариант не звонить WaitAll
вообще - если вы этого не сделаете, Result
свойства будут блокироваться, пока задача не завершится. Это означает, что вы все равно заблокируете поток (может быть немного большее количество блокировок, но я не уверен, сильно ли это влияет на производительность). Если вы используете List.map
чтобы собрать все результаты, поведение будет почти таким же.
Это неудачный дизайн. Task.WaitAll использует ключевое слово C# params, чтобы вы могли указать несколько аргументов и сделать их массивом в методе. Он также использует неявное приведение C#, так что вы можете дать ему Task<T>
"S. В F# вы должны сделать это самостоятельно, приведя к явному преобразованию и преобразовав в массив:
let ts = [|
Task.Factory.StartNew(fun () -> 1)
Task.Factory.StartNew(fun () -> 2)
|]
Task.WaitAll(ts |> Seq.cast<Task> |> Array.ofSeq)
Теперь вы можете получить результаты от ts
,
Массив также имеет карту, поэтому нет причин, по которым вы не можете поместить задачи в массив.
Или вы можете преобразовать в массив только для ожидания...