Я намеренно не отвечу на ваш вопрос как таковой.Вместо этого я поделюсь подходом, который вы можете использовать для спасения, если вы случайно наткнетесь на асинхронные рабочие процессы.Хитрость заключается в том, чтобы полностью охватить исследовательский стиль программирования, поддерживаемый F #.
Давайте начнем с минимального асинхронного рабочего процесса, который может быть async { () }
.Оценка в FSI
let dummywf = async { () }
дает
val dummywf : Async<unit>
, показывающий, что значение dummywf
действительно является асинхронным рабочим процессом (хотя и является действительно фиктивным).
Асинхронные рабочие процессыможет быть составлен в последовательности, одним из самых простых может быть список [ dummywf ]
.Оценка этого показывает тип Async<unit> list
, который представляет искомый.
Теперь давайте вспомним сигнатуру Async.Parallel
метода , который равен seq<Async<'T>> -> Async<'T[]>
, то есть требуетсяпоследовательность асинхронных вычислений и превращает их в асинхронные вычисления, которые, в конечном итоге, будучи вычисленными посредством асинхронной оценки его членов, приведут к массиву значений 'T
.При проверке в FSI выражение
[ dummywf ] |> Async.Parallel
оценивается как значение типа Async<unit []>
, действительно.
Наконец, давайте материализуем это значение, составив его в простейшей форме Async.RunSynchronously<'T>
метод принимает Async <'T> (в нашем случае значение типа Async<unit []>
) и возвращает результат вычисления типа 'T
(в нашем случае unit []
. Оценка комбинированного выражения
[ dummywf ] |> Async.Parallel |> Async.RunSynchronously
дает [|()|]
, как и ожидалось.
После получения кристально ясного понимания вышеупомянутой композиции, которая ведет себя, как и ожидалось, но это слишком просто, чтобы продемонстрировать, что мы действительно построили полныйасинхронный рабочий процесс, давайте попробуем что-то еще более простое, но более впечатляющее. Давайте реализуем функцию типа int -> Async<unit>
, которая принимает аргумент int
, делает неблокирующую паузу, возвращает тот же unit
и как побочный эффектвыводит значение аргумента:
let wasteSomeTime x =
async {
do! Async.Sleep(100)
printfn "%d" x
}
Теперь давайте используем wasteSomeTime
, чтобы составить последовательность асинхронных вычислений с различными аргументами и оценить ее в компеВариант, аналогичный предыдущему:
let wasteful = [1..10] |> Seq.map wasteSomeTime // binds to seq<Async<unit>>
wasteful |> Async.Parallel |> Async.RunSynchronously |> ignore
Выход будет похож на
>
4
2
3
6
8
10
7
5
9
1
val it : unit = ()
, что делает очевидным асинхронное выполнение.
После гроккингаЯ уверен, что вы сможете самостоятельно ответить на свой первоначальный вопрос.