在 Erlang 中模拟同步通信有一个非常常见的技巧:
%% Process 'sender'
Ref = make_ref(),
'receiver' ! {self(), Ref, Message},
receive {ack, Ref} -> ok end,
...
%% Process 'receiver'
receive
{From, Ref, Message} ->
From ! {ack, Ref},
handle_msg(Message),
...
end
这让
sender
阻塞,直到 receiver
收到消息。然而,我正在寻找的是阻塞直到消息被“传递”,或者换句话说,直到消息进入接收进程的消息队列。重要性在于,我想将其与已经排队的消息顺序的假设结合起来,而不必等待从队列中选取消息(它甚至可能永远不会被选取,我不在乎) .
例如,给定:
%% Process 'sender'
send_deliver('receiver', first),
'proxy' ! second
%% Process 'receiver'
receive
unlock -> ok
end,
receive
X -> X
end
%% Process 'proxy'
receive
X -> 'receiver' ! X
end
%% Process 'unlocker'
timer:sleep(thousand_years()),
'receiver' ! unlock
我在这个例子中的目标是:
receiver
必须在
first
之前收到
second
消息有效负载应该是无关紧要的(例如,如果您翻转 first
second
,则必须首先接收 second
)sender
send_deliver/2
的调用上被阻塞多长时间不应该取决于 receiver
正在做什么(特别是,不应该强迫它等待 thousand_years
)我可以用元组包装消息并添加附加信息,就像同步发送技巧一样
在底层,它使用锁在本地进程之间传递消息,但一旦跨越节点边界,你就只能靠自己了。我会避免依赖不能保证保持不变的内部实现。
关于你的问题,当我遇到这个问题时,我所做的只是将
second
消息视为
first+second
并为接收者准备好接收无序接收的 first
消息:receiver() ->
receive
first ->
do_first(),
receive second -> do_second() end,
second -> do_first(), do_second(), receive first -> ok end end
end.
在此解决方案中,由您决定如何处理无序的
first
消息。您可以使用
reference()
来匹配 first
和 second
对,使用别名来停用接收器等...另一个选项是使消息流线性:
Sender -> Proxy -> Receiver
,其中
first
和 second
消息由代理发送