在以下代码中,do! ag.AsyncAdd (Some i)
或ag.AsyncAdd (Some i)
(在enqueue()
函数中)均起作用。它们之间有什么区别?看来do! ...
将使入队和出队电话更加混杂?怎么样?
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
最佳答案
从FSharpx source code(请参阅评论):
/// 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个项目),则不会阻塞排队线程。因此,当您将循环更改为更高的数目时,您将所有排队线程的所有迭代中类型为AsyncAdd的消息(在后台FSharpx使用MailboxProcessor-检查此类的文档)发送到MailboxProcessor队列中。这会减慢另一个操作agent.Scan的速度:
and fullQueue() =
agent.Scan(fun msg ->
match msg with
| AsyncGet(reply) -> Some(dequeueAndContinue(reply))
| _ -> None )
万一你放的时候做!在AsyncAdd之前,当队列中有500个项目时,您的入队线程将被阻塞,并且不会为MailboxProcessor生成其他消息,因此agent.Scan将快速运行。当出队线程接收一个项目并且它们的数量变为499时,新的入队线程将被唤醒并添加新的项目,然后转到下一个循环迭代,将新的AsyncAdd消息放入MailboxProcessor中,然后再次进入睡眠状态,直到出队时刻为止。因此,MailboxProcessor不会被一个排队线程的所有迭代的消息AsyncAdd所垃圾。注意:项目队列和MailboxProcessor消息队列是不同的队列。
关于f# - async {…AsyncAdd…}和async {…AsyncAdd…}有什么区别?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57651745/