简体   繁体   English

F#使异步 <Async<MyTpe> []&gt;异步 <MyType> []

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

I get some list of data from a HTTP call. 我从HTTP调用中获得了一些数据列表。 I then know what values to get for another HTTP call. 然后,我知道要为另一个HTTP调用获取什么值。 I would like to have everything be asynchronous. 我希望一切都是异步的。 But I need to use this data with Expecto 's testCaseAsync : string -> Async<unit> -> Test . 但是我需要将此数据与Expecto testCaseAsync : string -> Async<unit> -> Test So, my goal is to get a signature like so Async<Item>[] 因此,我的目标是获得像Async<Item>[]这样的签名

So, I would like to get a list of testCaseAsync . 因此,我想获取testCaseAsync的列表。

So, I basically have something like this: 所以,我基本上是这样的:

// 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
   }

If I run them in parallel I get: 如果我并行运行它们,我将得到:

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

So, that doesn't get me to Async<Item>[] . 因此,这并不能使我进入Async<Item>[] I'm not sure if this is possible. 我不确定这是否可行。 I would like to avoid Async.RunSynchronously for the API.getTable call since that can lead to deadlocks, right? 我想避免对API.getTable调用Async.RunSynchronously ,因为那样会导致死锁,对吗? It will most likely be called from a cached value ( memoized ) so I'm not sure that will make a difference. 它很可能会从缓存的值(已memoized )中调用,所以我不确定这会有所作为。

I guess I'll keep working on it unless someone else is more clever than me :-) Thanks in advance! 我想除非有人比我更聪明,否则我会继续努力:-)预先感谢!

In general, you cannot turn Async<Async<T>[]> into Async<T>[] . 通常,您不能将Async<Async<T>[]>转换为Async<T>[] The problem is that to even get the length of the array, you need to perform some operation asynchronously, so there is no way to "lift" the array outside of the async. 问题在于,即使要获取数组的长度,也需要异步执行一些操作,因此无法将数组“提升”到异步之外。 If you knew the length of the array in advance, then you can make this work. 如果您事先知道数组的长度,则可以进行此工作。

The following function turns Async<'T[]> into Async<'T>[] provided that you give it the length of the array. 以下函数将Async<'T[]>转换为Async<'T>[]只要您为其指定数组的长度即可。 As you figured out, the returned asyncs need to somehow share access to the one top-level async. 如您所知,返回的异步需要以某种方式共享对一个顶级异步的访问。 The easiest way of doing this I can think of is to use a task. 我能想到的最简单的方法是使用任务。 Adapting that for your use case should be easy: 根据您的用例进行调整应该很容易:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM