1

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) 中调用,所以我不确定这会有所作为。

我想我会继续努力,除非其他人比我更聪明:-) 在此先感谢!

4

1 回答 1

8

一般来说,你不能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] }  
  )
于 2017-06-29T20:56:29.090 回答