问题
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
Here is the source code of BlockingQueueAgent
:
https://github.com/fsprojects/FSharpx.Async/blob/master/src/FSharpx.Async/BlockingQueueAgent.fs
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?
回答1:
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.
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) }
来源:https://stackoverflow.com/questions/57455823/f-async-parallel-async-runsynchronously-only-uses-one-of-the-eight-cpu-core