展平F#中的嵌套异步序列

Vag*_*lov 3 f# asynchronous sequence

考虑一系列F#序列:

let seqOf123 = seq { for i in 1..3 do yield i }
let seqOf456 = seq { for i in 4..6 do yield i }
let seqOf789 = seq { for i in 7..9 do yield i }
Run Code Online (Sandbox Code Playgroud)

......以及包含所有这些内容的序列:

let seqOfSeqOfNums = 
    seq {
        yield seqOf123
        yield seqOf456
        yield seqOf789
    }
Run Code Online (Sandbox Code Playgroud)

现在我们有一系列序列,我们可以使用内置的Seq.concat函数展平,并在async子句中包装以异步执行:

let firstAsyncSeqOfNums = async { return Seq.concat seqOfSeqOfNums }
Run Code Online (Sandbox Code Playgroud)

我们得到了一个由9个数字组成的异步序列,并带有一个签名Async<seq<int>>,我们将回过头来.

现在考虑一系列异步序列:

let asyncSeqOf123 = async { return seqOf123 }
let asyncSeqOf456 = async { return seqOf456 }
let asyncSeqOf789 = async { return seqOf789 }
Run Code Online (Sandbox Code Playgroud)

......以及包含它们的序列:

let seqOfAsyncSeqOfNums = 
    seq {
        yield asyncSeqOf123
        yield asyncSeqOf456
        yield asyncSeqOf789
    }
Run Code Online (Sandbox Code Playgroud)

我们现在有一个类型的序列seq<Async<seq<int>>>.我们不能使用Seq.concat来展平这个,因为它是一系列异步序列.那么我们如何将它转换为Async<seq<int>>所有整数数据被展平的类型呢?我们可以尝试执行以下操作:

let secondAsyncSeqOfNums = 
    async {
        return seqOfAsyncSeqOfNums
        |> Seq.map (fun x -> x |> Async.RunSynchronously)
        |> Seq.concat
    }
Run Code Online (Sandbox Code Playgroud)

它看起来像它的工作:它有一个类型Async<seq<int>>,如果我们将它传递给Async.RunSynchronously它将产生相同的9个整数序列.但它产生相同序列的方式并不等同于上面出现的firstAsyncSeqOfNums.在生成单个平坦序列期间,secondAsyncSeqOfNums的实现为每个嵌套的整数序列调用Async.RunSynchronously.但这可以避免吗?请注意,我们正在生成一个异步展平序列,理想情况下,只需要对Async.RunSynchronly进行一次调用即可评估其内容.但是,如果没有Async.RunSynchronously被多次调用,我找不到重写代码的方法.

Car*_*ten 5

你在寻找这样的东西:

> let aMap f wf = async {                              
-    let! a = wf
-    return f a
-    };;

val aMap : f:('a -> 'b) -> wf:Async<'a> -> Async<'b>

> let aConcat wf = Async.Parallel wf |> aMap Seq.concat;;   

val aConcat : wf:seq<Async<#seq<'b>>> -> Async<seq<'b>>
Run Code Online (Sandbox Code Playgroud)