首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >异步{.AsyncAdd .}和异步{。AsyncAdd . }?

异步{.AsyncAdd .}和异步{。AsyncAdd . }?
EN

Stack Overflow用户
提问于 2019-08-26 04:25:57
回答 2查看 109关注 0票数 2

在下面的代码中,do! ag.AsyncAdd (Some i)ag.AsyncAdd (Some i) (在函数enqueue()中)都可以工作。他们之间有什么区别?似乎do! ...会使排队和退排队的呼叫更加混合?多么?

代码语言:javascript
复制
open FSharpx.Control

let test () =
    let ag = new BlockingQueueAgent<int option>(500)

    let enqueue() = async { 
        for i = 1 to 15 do 
            // ag.AsyncAdd (Some i) // works too
            do! ag.AsyncAdd (Some i) 
            printfn "=> %d" i }

    async {
        do! [ for i = 1 to 10 do yield enqueue() ] 
            |> Async.Parallel |> Async.Ignore
        for i = 1 to 5 do ag.Add None
    } |> Async.Start

    let rec dequeue() =
        async {
            let! m = ag.AsyncGet()
            match m with
            | Some v ->
                printfn "<= %d" v
                return! dequeue()
            | None -> 
                printfn "Done" 
        }

    [ for i = 1 to 5 do yield dequeue() ] 
    |> Async.Parallel |> Async.Ignore |> Async.RunSynchronously
    0
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-08-26 17:45:50

来自FSharpx源代码 (请参阅注释):

代码语言:javascript
复制
    /// Asynchronously adds item to the queue. The operation ends when
    /// there is a place for the item. If the queue is full, the operation
    /// will block until some items are removed.
    member x.AsyncAdd(v:'T, ?timeout) = 
      agent.PostAndAsyncReply((fun ch -> AsyncAdd(v, ch)), ?timeout=timeout)

当不使用do!时,如果队列已满,则不阻塞队列线程(队列中的500项在构造函数中状态)。因此,当您将循环更改为更高的数目时,您会从所有enqueue线程的所有迭代中发送消息(场景后面的FSharpx使用MailboxProcessor --检查该类的文档)来垃圾处理AsyncAdd队列。这减缓了另一个操作,agent.Scan:

代码语言:javascript
复制
        and fullQueue() = 
            agent.Scan(fun msg ->
              match msg with 
              | AsyncGet(reply) -> Some(dequeueAndContinue(reply))
              | _ -> None )
  • 因为队列中有很多AsyncAdd和AsyncGet。

以防万一,当你放的时候!在AsyncAdd之前,当队列中有500个条目时,您的队列线程将被阻塞,并且不会为MailboxProcessor生成额外的消息,因此agent.Scan将快速工作。当dequeue线程接受一个项而其数量变为499时,新的队列线程唤醒并添加新项,然后进入循环的下一次迭代,将新的AsyncAdd消息放入MailboxProcessor中,然后再次进入休眠状态,直到退出队列。因此,MailboxProcessor不会被一个队列线程的所有迭代的消息( AsyncAdd )垃圾处理。注意:项目队列和MailboxProcessor消息队列是不同的队列。

票数 3
EN

Stack Overflow用户

发布于 2019-08-26 04:56:10

在任何F#计算表达式中,任何以!结尾的关键字都往往意味着“根据这个块的规则专门处理这个关键字”。例如,在async { }块中,let!关键字的意思是“等待结果,然后将结果赋值给这个变量”,do!关键字的意思是“等待这个异步操作,但是丢弃结果,不将其分配给任何东西”。如果不使用do!关键字,则不会等待该操作的结果。

因此,在您的do!函数中使用一个enqueue关键字,可以执行以下十五次操作:

  • 启动AsyncAdd操作
  • 等待它完成
  • 打印"=> 1“(或2或3.)

如果不使用关键字(一个do!关键字),您将执行以下操作:

  • 尽快启动15个AsyncAdd操作
  • 在每一个开始后,打印"=> 1“(或2或3.)

听起来你还没有完全理解F#的计算表达式是如何在幕后工作的。我建议阅读Scott的优秀网站,以获得更多的理解:首先是https://fsharpforfunandprofit.com/posts/concurrency-async-and-parallel/,然后是https://fsharpforfunandprofit.com/series/computation-expressions.html,这样当你阅读第二系列文章时,你就会在现有知识的基础上建立起来。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57651745

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档