1

Learn you some Erlang using standard IO functionsの kitchen モジュールを変更して、何が実行順に出力されるかを確認したところ、非常に奇妙なことがわかりました。基本的に、シェルで次を実行しました

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

0 が出力された直後に store 関数の receive 句の前に関数 store が関数 fridge2 を呼び出し、次に 2 が出力された後に receive 句が実行され、最終的に 1 が出力されるようです。変更後のコードは以下です。ストア関数から冷蔵庫2関数を呼び出す方法は? これはどういうわけか並列実行のためですか?この行は{Pid, Msg} ->store 関数で何をしますか? 関数呼び出しですか?そして、なぜokが印刷されるのですか?

-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.
4

1 に答える 1

1

caseステートメントと同様に、receiveはパターンマッチングを使用して、実行する句を決定します。 {Pid, Msg}任意の2タプルに一致する句です。

コードの実行について説明します-

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

これにより、関数を実行する新しいプロセスが生成されkitchen:fridge2/1ます。{From, {[store|take], Food}}その関数は、形式の2タプルまたはアトム'terminate'のいずれかであるメッセージを受信するまでブロックします。

kitchen:store(Pid, water).

その間に、シェルから上記の関数を呼び出します。メッセージ{self(), {store, Food}}をその新しいプロセスに送信し、「0」を出力してから、2タプルのメッセージを受信するのを待ちます。

もう一方のプロセスは、受信を満足させるメッセージを受信しました。メッセージを送信したプロセスにメッセージを{self(), ok}送り返し、「2」を出力し、再帰的に自分自身を呼び出し、再びメッセージの受信を待ちます。

シェルプロセスはメッセージを受信し、実行を継続します。「1」を出力してから、受け取ったタプルの2番目の要素(「ok」)を出力します。最後に、シェルに「ok」を返します。

シェルは結果( "ok")を出力し、プロンプトを表示します。

2番目のプロセスはまだメッセージの受信を待機しています。

于 2013-02-16T22:33:19.120 に答える