我有以下代码
let rec consume() : Async<unit> = async {
.....
listA
|> Seq.iter(fun i ->
.....
let listB : seq<...> option =
let c = getListB a b
match c with
| Some d -> Seq.filter(....) |> Some
| None -> None
match listB with .....
....
现在,函数getListB
已转换为返回async<Seq<B>>
而不是Seq<B>
。所以代码转换为以下内容。但是,getListB
阻止了执行。如何重写非阻塞?只需将行转换为let! c = getListB a b
即可,因为代码位于内部lambda中?错误消息是&#34;此构造只能在计算表达式中使用&#34;。
let rec consume() : Async<unit> = async {
.....
listA
|> Seq.iter(fun i ->
.....
let listB : seq<...> option =
let c = getListB a b |> Async.RunSynchronously
match c with
| Some d -> Seq.filter(....) |> Some
| None -> None
答案 0 :(得分:2)
答案取决于您是要按顺序还是并行运行序列的每个元素。
在这两种情况下,首先使用Seq.map
而不是Seq.iter
,然后您可以在lambda中放置另一个async
块,以使map
的结果为{ {1}}。
<强>顺序强>
为此,您需要在额外的seq<Async<'a>>
模块中定义一些额外的功能。
Async
您可能在其他地方看到module Async =
let map f x =
async{
let! x = x
return f x
}
let lift2 f x1 x2 =
async{
let! x1 = x1
let! x2 = x2
return f x1 x2
}
let return' x = async { return x }
let mapM mFunc sequ =
let consF x ys = lift2 (fun h t -> h::t) (mFunc x) ys
Seq.foldBack(consF) sequ (return' [])
|> map (Seq.ofList)
let sequence sequ = mapM id sequ
被称为mapM
,它们基本上只是同一概念的不同名称。
traverse
函数只是sequence
的特例,其中提供的绑定函数只是标识(mapM
)函数。它的类型为id
,即它会将seq<Async<'a>> -> Async<seq<'a>>
从Async
内翻到外面。
然后,您只需将Seq
的结果传输到Seq.map
函数,该函数会为您提供sequence
值。
您的示例代码不完整所以我编写了一些示例代码来使用它:
async
let sleep = Async.Sleep 100 let sleeps = Seq.init 15 (fun _ -> sleep) let sequencedSleeps = Async.sequence sleeps Async.RunSynchronously sequencedSleeps
<强>并行强>
要并行执行序列的每个元素,而不是按顺序执行:
Real: 00:00:01.632, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
val it : seq<unit> =
[null; null; null; null; null; null; null; null; null; null; null; null;
null; null; null]
示例测试代码:
let pSequence sequ = Async.Parallel sequ |> Async.map (Seq.ofArray)
let pSleeps = pSequence sleeps;; Async.RunSynchronously pSleeps;;
请注意执行时间取决于所选择的方法。
对于你回来Real: 00:00:00.104, CPU: 00:00:00.000, GC gen0: 0, gen1: 0, gen2: 0
val it : seq<unit> = seq [null; null; null; null; ...]
并因此想要忽略结果的情况,定义一些额外的辅助函数会很有用,例如:
seq<unit>
这可以让你返回一个let sequenceIgnore sequ = sequ |> Async.sequence |> Async.map (ignore)
let pSequenceIgnore sequ = sequ |> pSequence |> Async.map (ignore)
而不是多余的序列。
答案 1 :(得分:2)
我认为您所描述的问题归结为如何将seq<Async>
转换为Async<seq>
。 Scott Wlaschin在this post中对此进行了全面描述。
这是一个穷人在他的帖子中描述的概念的实现,它们更加强大和通用。一般的想法是我们想要延迟序列的创建,直到我们拥有Async<_>
let traverseSequence ( seqAsync : seq<Async<'a>>) =
let promiseOfAnEmptySequence = async { return Seq.empty }
let delayedCalculation (asyncHead : Async<'a>) (asyncTail : Async<seq<'a>>) =
async {
let! calculatedHead = asyncHead
return!
async {
let! calculatedTail = asyncTail
return calculatedHead |> Seq.singleton |> Seq.append(calculatedTail)
}
}
Seq.foldBack delayedCalculation seqAsync promiseOfAnEmptySequence