我正在尝试使用AsyncSeq,我对我遇到的速度问题感到困惑。以下是fiddle代码。
open System
open FSharpx.Control
let rec numbers n x = asyncSeq {
yield n
//printfn "%A" n
do! Async.Sleep(1)
if (n + 1 = x) then
yield n + 1
else
yield! numbers (n + 1) x
}
Async.Sleep(300) |> Async.RunSynchronously
for i in [0..300] do printfn "%A" i
numbers 0 300
|> AsyncSeq.iter (fun x -> printfn "%A" x)
|> Async.RunSynchronously
顶部循环在较短的时间内完成。底部异步序列需要更长时间。这是正常的吗?或者我错过了什么?
答案 0 :(得分:2)
异步序列设计用于编写涉及某些异步等待的计算,例如磁盘或网络I / O.出于这个原因,在使用asyncSeq
时期望一些开销是非常明智的 - 在典型的用例中,与异步操作的开销相比,这并不是非常重要。
我快速查看了您的示例,此处的大部分开销实际上来自Async.Sleep(1)
- 这在内部使用System.Threading.Timer
(计划在线程池中调用继续)。 / p>
在我的机器上,以下代码(Async.Sleep
)大约需要4.6秒:
let rec numbers n x = asyncSeq {
yield n
do! Async.Sleep(1) // (sleep)
if (n < x) then yield! numbers (n + 1) x }
numbers 0 300
|> AsyncSeq.iter (fun x -> printfn "%A" x)
|> Async.RunSynchronously
但是当您放弃Async.Sleep
调用(标记为(sleep)
的行)时,计算只需30ms,这与以下for
循环几乎相同:
for i in [0..300] do
printfn "%A" i
现在,如果向for
循环添加异步休眠,则需要5秒钟:
for i in [0..300] do
Async.Sleep(1) |> Async.RunSynchronously
printfn "%A" i
这并不太令人惊讶 - 如果用Thread.Sleep
替换异步休眠,那么它会运行得更快(但同步)。所以,总结一下:
asyncSeq
本身肯定会有一些开销,但它不是那么大Async.Sleep
Async.Sleep
等玩具示例衡量性能开销可能会产生误导: - )