考虑一系列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被多次调用,我找不到重写代码的方法。
答案 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>>