F#Make Async <async <mytpe> []&gt;到Async <mytype> []

时间:2017-06-29 20:25:03

标签: asynchronous f# expecto

我从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 个答案:

答案 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] }  
  )