简体   繁体   English

F#AsyncSeq速度问题

[英]F# AsyncSeq speed issue

I am trying out AsyncSeq and I am confused by a speed issue I am having. 我正在尝试AsyncSeq,但对速度问题感到困惑。 Here is a fiddle of the code below. 这是下面代码的小提琴

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

The top loop finishes clearly in a shorter amount of time. 顶部循环显然可以在更短的时间内完成。 While the bottom async sequence takes longer. 而底部异步序列需要更长的时间。 Is this normal? 这正常吗? or am I missing something? 还是我错过了什么?

Asynchronous sequences have been designed for writing computations that involve some asynchronous waiting such as disk or network I/O. 异步序列已被设计用于编写涉及一些异步等待的计算,例如磁盘或网络I / O。 For this reason, it is quite sensible to expect some overhead when using asyncSeq - in the typical use case, this is not very significant compared to the overhead of the asynchronous operations. 因此,使用asyncSeq时会产生一些开销是非常明智的-在典型的用例中,与异步操作的开销相比,这不是很明显。

I had a quick look at your example and most of the overhead here is actually coming from Async.Sleep(1) - this uses System.Threading.Timer internally (to schedule the continuation to be called in a thread pool). 我快速浏览了一下您的示例,这里的大部分开销实际上来自Async.Sleep(1) -这在内部使用System.Threading.Timer (以计划在线程池中调用的延续)。

On my machine, the following code (with Async.Sleep ) takes about 4.6 seconds: 在我的机器上,以下代码(带有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

But when you drop the Async.Sleep call (line marked (sleep) ), the computation takes just 30ms, which is pretty much the same as the following for loop: 但是,当您放弃Async.Sleep调用(标为(sleep) )时,计算仅需30ms,这与以下for循环几乎相同:

for i in [0..300] do 
  printfn "%A" i

Now, if you add asynchronous sleeping to the for loop, it takes 5 seconds too: 现在,如果您将异步睡眠添加到for循环中,则也需要5秒钟:

for i in [0..300] do 
  Async.Sleep(1) |> Async.RunSynchronously
  printfn "%A" i

This is not too surprising - if you replaced asynchronous sleeping with Thread.Sleep , then it would run faster (but synchronously). 这并不奇怪-如果您用Thread.Sleep替换了异步睡眠,那么它将运行得更快(但可以同步)。 So, in summary: 因此,总而言之:

  • There is certainly some overhead of asyncSeq itself, but it is not that big 当然asyncSeq本身会有一些开销,但是那并不大
  • Most of the overhead in your example comes from asynchronous sleeping using Async.Sleep 您的示例中的大部分开销来自使用Async.Sleep异步睡眠
  • This is quite realistic model of typical uses of asynchronous sequences - they are designed for writing computations that do some asynchronous waiting 这是异步序列典型用法的相当真实的模型-它们旨在编写执行一些异步等待的计算
  • Measuring performance overhead using toy examples like Async.Sleep can be misleading :-) 使用诸如Async.Sleep类的玩具示例来衡量性能开销可能会产生误解:-)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM