erlang函数调用乱序?

时间:2013-02-16 21:00:54

标签: process erlang

我使用标准IO功能从Learn you some Erlang修改了厨房模块,看看按执行顺序打印出来的东西,我发现了一些非常奇怪的东西。基本上我在shell中运行了以下内容

3> Pid = spawn(kitchen, fridge2, [[baking_soda]]).
<0.41.0>
4> kitchen:store(Pid, water).
0
2
1
ok
ok

在我看来,函数存储在打印0之后,在存储函数中的receive子句之前调用函数fridge2,然后在打印2之后执行receive子句并最终打印1。修改后的代码如下。如何通过商店功能调用fridge2功能?这是因为并行执行吗?这行在商店功能中{Pid, Msg} ->做什么?这是函数调用吗?为什么打印好?

-module(kitchen).
-compile(export_all).

start(FoodList) ->
    spawn(?MODULE, fridge2, [FoodList]).

store(Pid, Food) ->
    Pid ! {self(), {store, Food}},
    io:format("~p~n", [0]),
    receive                 
        {Pid, Msg} -> 
            io:format("~p~n", [1]),
            io:format("~p~n", [Msg]),
            Msg
    end.

take(Pid, Food) ->
    Pid ! {self(), {take, Food}},
    receive
        {Pid, Msg} -> Msg
    end.

store2(Pid, Food) ->
    Pid ! {self(), {store, Food}},
    receive
        {Pid, Msg} -> Msg
    after 3000 ->
        timeout
    end.

take2(Pid, Food) ->
    Pid ! {self(), {take, Food}},
    receive
        {Pid, Msg} -> Msg
    after 3000 ->
        timeout
    end.

fridge1() ->
    receive
        {From, {store, _Food}} ->
            From ! {self(), ok},
            fridge1();
        {From, {take, _Food}} ->
            %% uh....
            From ! {self(), not_found},
            fridge1();
        terminate ->
            ok
    end.

fridge2(FoodList) ->
    receive
        {From, {store, Food}} ->
            From ! {self(), ok},
            io:format("~p~n", [2]),
            fridge2([Food|FoodList]);
        {From, {take, Food}} ->
            case lists:member(Food, FoodList) of
                true ->
                    io:format("~p~n", [3]),
                    From ! {self(), {ok, Food}},
                    fridge2(lists:delete(Food, FoodList));
                false ->
                    io:format("~p~n", [4]),
                    From ! {self(), not_found},
                    fridge2(FoodList)
            end;
        terminate ->
            ok
    end.

1 个答案:

答案 0 :(得分:1)

与case语句类似,receive使用模式匹配来确定要执行的子句。 {Pid, Msg}是一个匹配任何2元组的子句。

让我们一起来看看代码的执行情况 -

Pid = spawn(kitchen, fridge2, [[baking_soda]]).

这会生成一个执行kitchen:fridge2/1函数的新进程。该函数阻塞,直到它收到一个消息,该消息是{From, {[store|take], Food}}形式的2元组或原子'终止'。

kitchen:store(Pid, water).

同时,你从shell调用上面的函数。它将消息{self(), {store, Food}}发送到该新进程,打印“0”,然后等待接收一个2元组的消息。

现在,另一个进程收到了一条消息,表示已收到该消息。它将消息{self(), ok}发送回发送消息的进程,打印“2”,递归调用自身并再次等待接收消息。

shell进程现在收到一条消息并继续执行。它打印“1”然后打印它收到的元组的第二个元素(“ok”)。最后它返回'ok'到shell。

shell打印结果(“ok”)并显示提示。

第二个进程仍在等待接收消息。