erlang函数调用乱序?

Posted

技术标签:

【中文标题】erlang函数调用乱序?【英文标题】:erlang function call out of order? 【发布时间】:2013-02-01 15:06:13 【问题描述】:

我使用标准 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

在我看来,函数 store 在打印出 0 之后的 store 函数中的 receive 子句之前调用了函数 freezer2,然后在打印了 2 之后,执行了接收子句并最终打印了 1。修改后的代码如下。如何从 store 函数中调用冰箱函数?这是因为以某种方式并行执行吗?这行 Pid, Msg -&gt; 在 store 函数中是做什么的?是函数调用吗?为什么可以打印?

-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】:

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

让我们来看看你的代码的执行 --

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

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

kitchen:store(Pid, water).

同时,您从 shell 调用上述函数。它将消息self(), store, Food 发送到该新进程,打印“0”,然后等待接收二元组消息。

另一个进程现在收到了一条满足其接收要求的消息。它将消息self(), ok 发送回发送消息的进程,打印“2”,递归调用自身并再次等待接收消息。

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

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

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

【讨论】:

感谢您的信息。发布此主题后,我开始对代码有了更多的了解,但是您更加支持了我的理解,谢谢!

以上是关于erlang函数调用乱序?的主要内容,如果未能解决你的问题,请参考以下文章

Erlang中的函数调用方式.

为啥 erlang spawn 函数调用中出现语法错误 - “之前的语法错误:')'”?

Erlang 语言中的进程与并发

为什么语法错误会出现在erlang spawn函数调用中 - “语法错误之前:')'”?

Erlang堆栈跟踪中包含多少条目?

Elixir io_lib 调用 erlang