How exactly Erlang receive expression works?

2019-07-14 03:23发布

  • Why receive expression is sometimes called selective receive?
  • What is the "save queue"?
  • How the after section works?

标签: erlang elixir
2条回答
做个烂人
2楼-- · 2019-07-14 03:33

Why receive expression is sometimes called selective receive?

-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").

start() ->
    spawn(my, go, []).

go() ->
    receive
        {xyz, X} ->
            io:format("I received X=~w~n", [X])
    end.

In the erlang shell:

1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}

2> Pid = my:start().                
<0.79.0>

3> Pid ! {hello, world}.
{hello,world}

4> Pid ! {xyz, 10}.     
I received X=10
{xyz,10}

Note how there was no output for the first message that was sent, but there was output for the second message that was sent. The receive was selective: it did not receive all messages, it received only messages matching the specified pattern.

What is the "save queue"?

-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").

start() ->
    spawn(my, go, []).

go() ->
    receive
        {xyz, X} ->
            io:format("I received X=~w~n", [X])
    end,
    io:format("What happened to the message that didn't match?"),
    receive 
        Any ->
            io:format("It was saved rather than discarded.~n"),
            io:format("Here it is: ~w~n", [Any])
    end.

In the erlang shell:

1> c(my).               
my.erl:3: Warning: export_all flag enabled - all functions will be exported 
{ok,my}

2> Pid = my:start().    
<0.79.0>

3> Pid ! {hello, world}.
{hello,world}

4> Pid ! {xyz, 10}.     
I received X=10
What happened to the message that didn't match?{xyz,10}
It was saved rather than discarded.
Here it is: {hello,world}

How the after section works?

-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").

start() ->
    spawn(my, go, []).

go() ->
    receive
        {xyz, X} ->
            io:format("I received X=~w~n", [X])
    after 10000 ->
        io:format("I'm not going to wait all day for a match.  Bye.")
    end.

In the erlang shell:

1> c(my).           
my.erl:3: Warning: export_all flag enabled - all functions will be exported 
{ok,my}

2> Pid = my:start().
<0.79.0>

3> Pid ! {hello, world}.
{hello,world}
I'm not going to wait all day.  Bye.4> 

Another example:

-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").

sleep(X) ->
    receive
    after X * 1000 ->
        io:format("I just slept for ~w seconds.~n", [X])
    end.

In the erlang shell:

1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported 
{ok,my}

2> my:sleep(5).                   
I just slept for 5 seconds.
ok
查看更多
我只想做你的唯一
3楼-- · 2019-07-14 03:48

There is a special "save queue" involved in the procedure that when you first encounter the receive expression you may ignore its presence.

Optionally, there may be an after-section in the expression that complicates the procedure a little.

The receive expression is best explained with a flowchart:

receive
  pattern1 -> expressions1;
  pattern2 -> expressions2;
  pattern3 -> expressions3
after
  Time -> expressionsTimeout
end

Erlang receive

查看更多
登录 后发表回答