一、邮箱的概念
① 每个进程都带有一个邮箱,这个邮箱是和进程同步创建的。
② 给某个进程发送消息后,消息会被放入该进程的邮箱。只有当程序执行第一条接收语句时才会读取邮箱。
二、问题的疑惑
源代码 tester.erl
-module(trec).
-export([start/0]).
start() ->
receive
{alarm, Content} -> io:format("bbb")
after 0 ->
receive
Any -> io:format("xxx")
end
end.
c(trec).
Pid = spawn(trec, start, []).
Pid ! {alarm, 123}.
> xxx{alarm, 123}.
当邮箱中出现 {alarm, Content} 时会优先处理对应的表达式并返回,只有当模式匹配都完成后,才能执行 after 0 后面的部分。
那为什么向该进程发送了 {alarm, 123} 却没有打印出 bbb,反而打印出 xxx 并退出了该进程。
原因:spawn() 创建进程的同时,执行了程序代码,一旦程序代码执行,就会立即读取邮箱的消息,而此时,Pid ! {alarm, 123} 的消息还没有发送给该进程,因此邮箱消息为空,直接执行了 after 0 后面的语句,接收到任一一个参数,就输出 xxx 并退出进程。
换个方式看看:
c(trec).
self() ! {alarm, 123}. % 向当前shell的进程邮箱发送一条消息
trec:start(). % 执行代码,读取当前进程的邮箱,能获取到{alarm, 123}消息
> bbbok
分享一段代码分析:
-module(multiproc).
-export([important/0]).
important() ->
receive
{Priority, Message} when Priority > 10 ->
[Message | important()]
after 0 ->
normal()
end.
normal() ->
receive
{_, Message} ->
[Message | normal()]
after 0 ->
[]
end.
1> c(multiproc).
{ok,multiproc}
2> self() ! {15, high}, self() ! {7, low}, self() ! {1, low}, self() ! {17, high}.
% 依次向当前shell进程邮箱发送{15, high} {7, low} {1, low} {17, high} 消息
{17,high}
3> multiproc:important().
[high,high,low,low]
% 由于第一个消息 {15, high} 条件1,则执行表达式,并将该消息从邮箱内删除。由于第2、3条消息 {7, low} {1, low} 不满足条件1,保留在邮箱的“保存队列”内并从邮箱里删除,第4条满足则执行表达式并从邮箱里删除。然后执行 after 的代码,读取邮箱内剩余的 2、3 条消息,得到最终结果
不错的erlang after分析链接:https://learnyousomeerlang.com/more-on-multiprocessing