使用Post或PostAndAsyncReply与F#的MailboxProcessor?

时间:2011-12-15 17:25:11

标签: concurrency f# actor mailboxprocessor

我看到了不同的代码段,展示了Put消息,该消息通过F#的unit返回MailboxProcessor。在某些情况下,仅使用Post方法,而其他方法使用PostAndAsyncReply,一旦处理完消息,回复通道立即回复。在进行一些测试时,我在等待回复时发现了一个显着的时滞,所以看起来除非你需要真正的回复,否则你应该使用Post

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

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

更新

我刚刚想到了BlockingQueueAgent example中可能需要PostAndAsyncReply的原因:Scan用于在队列已满时查找Get消息,所以你不要在上一个Put完成之前,我想要Get然后Put

2 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:3)

我认为我一般都同意你的摘要 - PostAndAsyncReply慢于Post是有意义的,所以如果调用者在操作时不需要从代理获得通知(例如在将值放入队列中)完成后,它应该只使用Post公开一种方法。 PostAndAsyncReply慢得多的事实可能意味着某些代理应该公开这两个选项并让调用者决定。

关于BlockingQueueAgent的具体示例(或我用于实现单位缓冲区的类似示例),代理的典型应用是解决消费者 - 生产者问题。在消费者 - 生产者问题中,我们希望在队列满时阻止生产者,并在消费者为空时阻止消费者。 .NET BlockingCollection仅支持同步阻塞,这有点不好(即它可以阻塞整个线程池)。

使用使用BlockingQueueAgent发送Put消息的PostAndAsyncReply,我们可以等到元素异步添加到队列中(因此它会阻塞生成器,但不会阻塞线程!)典型用法的一个例子是我前段时间写的image processing pipeline。这是一个片段:

// 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) }

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