Ожидается, что это выражение будет иметь тип 'unit', но здесь имеет тип 'unit []' для Async.Parallel |> Async.RunSynchronously - PullRequest
0 голосов
/ 08 июня 2018

У меня есть следующий код в основной функции консольного приложения F #.

let main ... = 
    let list = // get a list
    list 
    |> Seq.iter(fun i -> ....)
    ()

Затем я попытался запустить элементы параллельно.

let list = // get a list
list 
|> Seq.map(fun i -> async { .... })
|> Seq.toArray
|> Async.Parallel
|> Async.RunSynchronously // ERROR
// |> ignore
()

И он получилошибка

Error   FS0001  This expression was expected to have type
    'unit'    
but here has type
    'unit []'   

Добавление |> ignore приведет к тому, что F # не запустит код в Seq.map().

1 Ответ

0 голосов
/ 08 июня 2018

Я намеренно не отвечу на ваш вопрос как таковой.Вместо этого я поделюсь подходом, который вы можете использовать для спасения, если вы случайно наткнетесь на асинхронные рабочие процессы.Хитрость заключается в том, чтобы полностью охватить исследовательский стиль программирования, поддерживаемый 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 = ()

, что делает очевидным асинхронное выполнение.

После гроккингаЯ уверен, что вы сможете самостоятельно ответить на свой первоначальный вопрос.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...