我从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
)调用的,因此我不确定这会产生什么影响。
我想我会继续努力,除非别人比我更聪明:-)提前谢谢!
答案 0 :(得分:8)
一般情况下,您无法将Async<Async<T>[]>
变为Async<T>[]
。问题是,要获得数组的长度,您需要异步执行某些操作,因此无法在异步之外“提升”数组。如果您事先知道阵列的长度,那么您可以使其工作。
以下函数将Async<'T[]>
变为Async<'T>[]
,前提是您为其指定数组的长度。正如您所知,返回的asyncs需要以某种方式共享对一个顶级异步的访问权限。我能想到的最简单的方法是使用任务。根据您的用例进行调整应该很容易:
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] }
)