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

时间:2015-04-06 08:58:34

标签: asynchronous f# 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 }

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

let seqOfSeqOfNums = 
    seq {
        yield seqOf123
        yield seqOf456
        yield seqOf789
    }

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

let firstAsyncSeqOfNums = async { return Seq.concat seqOfSeqOfNums }

我们有一个9个号码的异步序列,签名Async<seq<int>>我们将回来。

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

let asyncSeqOf123 = async { return seqOf123 }
let asyncSeqOf456 = async { return seqOf456 }
let asyncSeqOf789 = async { return seqOf789 }

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

let seqOfAsyncSeqOfNums = 
    seq {
        yield asyncSeqOf123
        yield asyncSeqOf456
        yield asyncSeqOf789
    }

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

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

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

1 个答案:

答案 0 :(得分: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>>