F#Make Async <Async <MyTpe> []> to Async <MyType> []

Jon*_*n49 1 f# asynchronous expecto

我从HTTP呼叫中获得了一些数据列表.然后我知道另一个HTTP电话会得到什么值.我希望一切都是异步的.但我需要使用这个数据Expecto 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
   }
Run Code Online (Sandbox Code Playgroud)

如果我并行运行它,我得到:

// Async<Item[]>
let getAsyncCalls =
   async {
       let! table = API.getTable ()
       // Item[]
       let! items =
           table.root
           |> Array.map (fun x -> API.getItem x.id)
       return item
   }
Run Code Online (Sandbox Code Playgroud)

所以,这不会让我这么做Async<Item>[].我不确定这是否可行.我想避免Async.RunSynchronouslyAPI.getTable,因为该呼叫会导致死锁,对不对?它很可能是从缓存的值(memoized)中调用的,因此我不确定这会产生什么影响.

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

Tom*_*cek 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] }  
  )
Run Code Online (Sandbox Code Playgroud)