【发布时间】:2017-06-26 09:42:35
【问题描述】:
我正在使用代理 (MailboxProcessor) 来执行一些需要响应的有状态处理。
- 来电者使用
MailboxProcessor.PostAndAsyncReply发布消息 - 在代理中,以
AsyncReplyChannel.Reply给出响应
但是,通过查看 f# 源代码,我发现代理在响应传递之前不会处理下一条消息。总的来说,这是一件好事。但在我的情况下,代理更希望继续处理消息而不是等待响应传递。
做这样的事情来传递响应是否有问题? (或者有更好的选择吗?)
async { replyChannel.Reply response } |> Async.Start
我知道这种方法不能保证响应会按顺序传递。我没关系。
参考示例
// agent code
let doWork data =
async { ... ; return response }
let rec loop ( inbox : MailboxProcessor<_> ) =
async {
let! msg = inbox.Receive()
match msg with
| None ->
return ()
| Some ( data, replyChannel ) ->
let! response = doWork data
replyChannel.Reply response (* waits for delivery, vs below *)
// async { replyChannel.Reply response } |> Async.Start
return! loop inbox
}
let agent =
MailboxProcessor.Start(loop)
// caller code
async {
let! response =
agent.PostAndAsyncReply(fun replyChannel -> Some (data, replyChannel))
...
}
【问题讨论】:
-
您尝试做的事情有点违背
PostAndAsyncReply的观点,那么为什么要使用它呢?让客户传入一个可观察的主题,然后将您的回复推送到其中。 -
必须以任何一种方式(使用可观察或使用回复通道)支付同步成本以传递响应。问题中使用的方法没有添加额外的代码行,也没有引入新概念。但是,如果您可以确定其他权衡并提供一个示例,那将是一个很好的答案。
-
您自己已经确定了权衡:回复渠道不能乱序工作。
-
让我看看我是否正确理解了您的目标: 1. 您希望代理不要等待消息传递,以便在上一条消息在传输过程中继续处理消息 2. 您希望调用者同步处理消息?
-
@mydogisbox 1 是的。 2 否。调用者也在异步操作中,当提供响应时它会恢复。上一条评论中提到的“同步成本”与在后台协调线程的成本有关。 IE。 f#
AsyncReplyChannel在内部使用ManualResetEvent来表示结果准备就绪。所以当Reply被调用时,它不会返回,直到响应被传递。这个有效的让代理等到调用者收到响应后再处理下一条消息。
标签: f# agent mailboxprocessor