F#Async.Parallel |> Async.RunSynchronously仅使用八个CPU内核之一? [英] F# Async.Parallel |> Async.RunSynchronously only uses one of the eight CPU core?

查看:85
本文介绍了F#Async.Parallel |> Async.RunSynchronously仅使用八个CPU内核之一?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个dotnet核心应用程序,并运行以下发行版代码.但是,PC的总CPU使用率仅为20%左右,而进程dotnet运行仅需12%(我有八个逻辑CPU,但我也看不到其中任何一个都使用100%). CPU不是代码的瓶颈吗?

I created a dotnet core application and run the following code of release build. However, the total CPU usage of the PC is around only 20% and process dotnet run takes only 12% (I have eight logical CPUs and I don't see any one of it use 100% either). Isn't the CPU the bottleneck of the code?

open FSharpx.Control

[<EntryPoint>]
let main argv =
    let ag = new BlockingQueueAgent<int option>(500)

    let enqueue() = async { for i = 0 to 1000 do ag.Add (Some i) }
    async {
        do! [ for i = 0 to 1000 do yield enqueue() ] 
            |> Async.Parallel |> Async.Ignore
        ag.Add None
    } |> Async.Start

    let mutable x = 0

    let rec dequeue() =
        async {
            let! m = ag.AsyncGet()
            match m with
            | Some v ->
                //x <- x ^^^ v
                for z = 0 to 10000 do x <- x + z
                return! dequeue()
            | None -> 
                printfn "Done %d" x
        }

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

这是BlockingQueueAgent的源代码: https://github.com/fsprojects/FSharpx.Async/blob/master/src/FSharpx.Async/BlockingQueueAgent.fs

更新: 添加了更复杂的代码(替换为x <- x ^^^ v).现在,它大量使用CPU内核.不过仍然是13%.为什么不使用多核?

Update: Added more complex code (repaced x <- x ^^^ v). Now it uses a CPU core a lot. Still 13% though. Why it doesn't use multiple core?

推荐答案

在开始使任何消息出队之前,您正在同步使所有Add操作入队.这意味着,当业务代表选择下一步做什么时,如果未满,它将始终将新项目Add放入队列.当已满时,它将搜索第一个AsyncGet操作并对其进行处理,但是随后会立即(同步)将下一个项目Add放入队列,然后再允许另一个消息出队.这实际上仅允许您一次使一条消息出队,因为该代理始终在AddAsyncGet操作之间来回切换.

You're synchronously enqueueing all of your Add operations before you start dequeuing any messages. This means that when the agent is choosing what to do next it will always Add a new item to the queue if it isn't full. When it is full, it will search for the first AsyncGet operation and process that, but then will immediately Add (synchronously) the next item to the queue before allowing another message to be dequeued. This effectively only allows you to dequeue one message at a time because the agent is always switching back and forth between Add and AsyncGet operations.

如果您执行AsyncAdd而不是Add,则入队和出队都可以异步发生,并且您将获得所需的行为,即

If you do an AsyncAdd instead of an Add then both enqueuing and dequeueing can happen asynchronously and you get the desired behaviour, i.e.

let enqueue() = async { for i = 0 to 1000 do do! ag.AsyncAdd (Some i) }

这篇关于F#Async.Parallel |&gt; Async.RunSynchronously仅使用八个CPU内核之一?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆