首页 > 解决方案 > Fire and no-wait (without do!) vs Fire and await (do!) 有巨大的差异表现?

问题描述

以下代码需要大约 20 秒才能运行。但是,取消注释后不到一秒钟do!。为什么会有如此巨大的差异?

更新: 使用时需要 9 秒ag.Add。我已经更新了代码。

open FSharpx.Control

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

    let enqueue() = async { 
        for i = 1 to 500 do 
            //do! ag.AsyncAdd (Some i) // less than a second with do!
            ag.AsyncAdd (Some i)       // it takes about 20 seconds without do!
            //ag.Add (Some i)          // This one takes about 9 seconds
            //printfn "=> %d" i 
            }

    async {
        do! [ for i = 1 to 100 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

标签: f#

解决方案


没有do!,您不会等待 的结果AsyncAdd。这意味着AsyncAdd每次调用enqueue(). AsyncAdd虽然如果队列已满,每个调用都会阻塞,但如果你不等待结果,AsyncAdd那么你的enqueue()代码不会被阻塞,它会继续启动新的AsyncAdd操作。

由于您要enqueue()并行启动 100 个操作,因此可能有多达五万个 AsyncAdd操作将尝试同时运行,这意味着线程池正在处理 49,500 个阻塞线程。这对你的系统有很多要求。在实践中,您不会同时启动 100 个enqueue()并行操作,但您将启动与enqueue()逻辑 CPU 一样多的操作。对于这个答案的其余部分,我将假设您有一个具有超线程的四核处理器(因为您的F# Async.Parallel |> Async.RunSynchronously 只使用八个 CPU 核心之一?问题似乎暗示了),所以这是 8 个逻辑 CPU,所以你将enqueue()在任何阻塞之前启动 8 个副本,这意味着你AsyncAdd正在运行的线程,其中 3,500 个将被阻塞。

do!另一方面,当您使用时,如果AsyncAdd被阻塞,您的enqueue()操作也会阻塞,直到队列中有一个空位。因此,一旦队列中有 500 个项目,而不是 (8*500 - 500 = 3500) 个阻塞AsyncAdd线程位于线程池中,将有 8 个阻塞AsyncAdd线程(一个用于enqueue()在您的八个逻辑中的每一个上运行的八个操作中的每个CPU)。八个阻塞线程而不是 3,500 意味着线程池没有进行 3,500 次分配,使用更少的 RAM 和更少的 CPU 时间来处理所有这些线程。

正如我在回答您之前的问题时所说的那样,您似乎确实需要对异步操作有更深入的了解。除了我在该答案中链接的文章(本文本系列),我还将推荐阅读https://medium.com/jettech/f-async-guide-eb3c8a2d180a这是一个相当长且详细的指南到 F# 异步操作和您可能遇到的一些“陷阱”。我强烈建议您阅读这些文章,然后再回来查看您的问题。随着您从阅读这些文章中获得更深入的理解,您也许能够回答自己的问题!


推荐阅读