使用Post或PostAndAsyncReply与F#的MailboxProcessor?

5 concurrency f# actor mailboxprocessor

我已经看到了不同的片段,展示了Put一条unit用F#返回的消息MailboxProcessor.在某些情况下,只有Post方法被使用,而其他人使用PostAndAsyncReply,一旦处理消息,回复通道立即回复.在做一些测试时,我发现在等待回复时有很长的时间滞后,所以看起来除非你需要真正的回复,否则你应该使用Post.

注意:我开始在另一个帖子中询问这个问题,但认为发布完整问题很有用.在另一个帖子中,Tomas Petricek提到回复通道可以使用等待机制来确保调用者延迟直到Put消息被处理.

使用PostAndAsyncReply消息排序的帮助,还是只是强制暂停直到处理第一条消息?在性能方面Post出现了正确的解决方案.那是准确的吗?

更新:

我只想到了为什么PostAndAsyncReplyBlockingQueueAgent示例中可能需要的原因:Scan用于Get在队列已满时查找消息,因此您不希望在之前完成之前Put然后再查找消息.GetPut

Jon*_*rop 5

我的建议是设计您的系统,以便您可以Post尽可能多地使用。

该技术专为异步并发而设计,其目标是“即发即忘”消息。等待响应的想法直接违背了这一点。


Tom*_*cek 4

我想我总体上同意你的总结 - 它PostAndAsyncReply比 慢是有道理Post的,所以如果调用者在操作(例如将值放入队列)完成时不需要从代理那里获取通知,那么它绝对应该公开一种仅使用Post. 事实上,速度PostAndAsyncReply要慢得多,这可能意味着某些代理应该公开这两个选项并让调用者决定。

关于具体的例子BlockingQueueAgent(或者我用来实现一处缓冲区的类似例子),代理的典型应用是解决消费者-生产者问题。在消费者-生产者问题中,我们希望当队列已满时阻塞生产者,当队列为空时阻塞消费者。.NETBlockingCollection仅支持同步阻塞,这有点糟糕(即它可以阻塞整个线程池)。

使用BlockingQueueAgent发送Put消息PostAndAsyncReply的 ,我们可以等到元素被异步添加到队列中(因此它会阻塞生产者,但不会阻塞线程!)典型用法的一个例子是我前段时间写的图像处理管道。这是其中的一个片段:

// Phase 2: Scale to a thumbnail size and add frame
let scalePipelinedImages = async {
   while true do 
     let! info = loadedImages.AsyncGet()
     scaleImage info
     do! scaledImages.AsyncAdd(info) }
Run Code Online (Sandbox Code Playgroud)

该循环重复从队列中获取图像loadedImages,进行一些处理并将结果写入scaledImages. 使用队列的阻塞(读取和写入时)控制并行性,以便管道的步骤并行运行,但如果管道无法以所需的速度处理它们,则不会继续加载越来越多的图像。