F# Сделать Async<Async <MyTpe>[]> для Async<MyType>[]
Я получаю некоторый список данных из HTTP
вызов. Я тогда знаю, какие значения получить для другого HTTP
вызов. Я хотел бы, чтобы все было асинхронным. Но мне нужно использовать эти данные с Expecto
"s testCaseAsync : string -> Async<unit> -> Test
, Итак, моя цель - получить такую подпись Async<Item>[]
Итак, я хотел бы получить список testCaseAsync
,
Итак, у меня есть что-то вроде этого:
// Async<Async<Item>[]>
let getAsyncCalls =
async {
let! table = API.getTable ()
// Async<Item>[]
let items =
table.root
|> Array.map (fun x -> API.getItem x.id)
return item
}
Если я запускаю их параллельно, я получаю:
// Async<Item[]>
let getAsyncCalls =
async {
let! table = API.getTable ()
// Item[]
let! items =
table.root
|> Array.map (fun x -> API.getItem x.id)
return item
}
Так что это не заставляет меня Async<Item>[]
, Я не уверен, возможно ли это. Я хотел бы избежать Async.RunSynchronously
для API.getTable
звоните, так как это может привести к тупикам, верно? Скорее всего, он будет вызван из кэшированного значения (memoized
) поэтому я не уверен, что будет иметь значение.
Я думаю, я буду продолжать работать над этим, если кто-то еще не будет умнее меня:-) Заранее спасибо!
1 ответ
В общем, вы не можете включить Async<Async<T>[]>
в Async<T>[]
, Проблема в том, что даже для получения длины массива необходимо выполнить некоторую операцию асинхронно, поэтому нет способа "поднять" массив за пределы асинхронного. Если вы заранее знали длину массива, то можете сделать это.
Следующая функция превращается Async<'T[]>
в Async<'T>[]
при условии, что вы дадите ему длину массива. Как вы выяснили, возвращаемые асинхронные компоненты должны каким-то образом совместно использовать доступ к одной асинхронной системе верхнего уровня. Самый простой способ сделать это - использовать задачу. Адаптировать его для вашего случая использования должно быть легко:
let unwrapAsyncArray (asyncs:Async<'T[]>) len =
let task = asyncs |> Async.StartAsTask
Array.init len (fun i -> async {
let! res = Async.AwaitTask task
if res.Length <> len then failwith "Wrong length!"
return res.[i] }
)