Выполнение параллельного примера в коде Erlang из командной строки

Я тестирую код из Руководство пользователя по началу работы с Erlang Параллельное программирование Раздел.

В tut17.erl я запустил процесс с erl -sname ping и еще один процесс с al -sname pong, как описано в руководстве.

-module(tut17).
-export([start_ping/1, start_pong/0, ping/2, pong/0]).

ping(0, Pong_Node) ->
    {pong, Pong_Node} ! finished, 
    io:format("ping finished~n", []);

ping(N, Pong_Node) ->
    {pong, Pong_Node} ! {ping, self()}, 
    receive
        pong ->
            io:format("Ping received pong~n", [])
    end,        
    ping(N - 1, Pong_Node).

pong() ->
    receive
        finished -> io:format("Pong finished~n", []);
        {ping, Ping_PID} -> 
            io:format("Pong received ping~n", []), 
            Ping_PID ! pong,
            pong() 
    end.

start_pong() ->
    register(pong, spawn(tut17, pong, [])).

start_ping(Pong_Node) ->
    spawn(tut17, ping, [3, Pong_Node]).

Из процесса пинга и понга я мог вызвать start_ping и start_pong, чтобы убедиться, что все работает нормально.

(ping@smcho)1> tut17:start_ping(pong@smcho).
<0.40.0>
Ping received pong
Ping received pong
Ping received pong
ping finished  

(pong@smcho)2> tut17:start_pong().
true
Pong received ping
Pong received ping
Pong received ping
Pong finished 

Я пытаюсь запустить тот же код из командной строки; Для простого примера hello world:

-module(helloworld).
-export([start/0]).

start() ->
    io:fwrite("Hello, world!\n").

Я использую следующую командную строку:

erlc helloworld.erl
erl -noshell -s helloworld start -s init stop

Итак, я просто попробовал следующее, но в итоге произошел сбой.

  • От узла ping: erl -noshell -sname ping -s tut17 start_ping pong@smcho -s init stop
  • От узла понг: erl -noshell -sname pong -s tut17 start_pong -s init stop

Однако я получил этот отчет об ошибке от ping, когда pong заканчивается, ничего не печатая.

=ERROR REPORT==== 6-Mar-2015::20:29:24 ===
Error in process <0.35.0> on node 'ping@smcho' with exit value: 
    {badarg,[{tut17,ping,2,[{file,"tut17.erl"},{line,9}]}]}

По сравнению с подходом REPL, с командной строкой, каждый процесс не ждет ответа от партнера, а останавливается через некоторое время. Что может быть не так?


person prosseek    schedule 07.03.2015    source источник


Ответы (2)


Аргументы из командной строки принимаются в виде списка атомов при использовании ключа -s и списка строк при использовании ключа -run. Имея это в виду, давайте подумаем, что происходит...

Эта команда выдается из оболочки:

erl -noshell -sname ping \
    -s tut17 start_ping pong@smcho \
    -s init stop

Итак, start_ping/1 вызывается с аргументом [pong@smcho]. Затем он вызывает ping/2 как ping(3, [pong@smcho]), который в своей первой строке пытается сделать {pong, [pong@smcho]} ! {ping, self()}. Поскольку список не является допустимой целью для сообщения... ваш мир взрывается.

Чтобы удобно запускать это как из оболочки Erlang, так и из системной оболочки, вы можете добавить предложение к start_ping/1:

start_ping([Pong_Node]) ->
    spawn(tut17, ping, [3, Pong_Node]);
start_ping(Pong_Node) ->
    start_ping([Pong_Node]).
person zxq9    schedule 07.03.2015

Необходимы некоторые изменения.

start_ping

По подсказке zxq9 я изменил функцию start_ping.

start_ping([Pong_Node]) ->
    io:format("Ping started~n", []),
    spawn(tut17, ping, [3, Pong_Node]);
start_ping(Pong_Node) ->
    start_ping([Pong_Node]).

Вызовите init:stop(), когда процесс завершится.

Я не уверен, что это абсолютно необходимо, но, похоже, это работает с этой модификацией.

ping(0, Pong_Node) ->
    {pong, Pong_Node} ! finished, 
    io:format("ping finished~n", []),
    init:stop();

Тогда я мог бы удалить -s init stop из команды оболочки: erl -noshell -sname ping -s tut17 start_ping pong@smcho.

Порядок выполнения

Pong должен вызываться до вызова Ping.

Обновленный код

Это пересмотренный код:

-module(tut17).
-export([start_ping/1, start_pong/0, ping/2, pong/0]).

ping(0, Pong_Node) ->
    {pong, Pong_Node} ! finished, 
    io:format("ping finished~n", []),
    init:stop();
ping(N, Pong_Node) ->
    {pong, Pong_Node} ! {ping, self()}, 
    receive
        pong ->
            io:format("Ping received pong~n", [])
    end,        
    ping(N - 1, Pong_Node).

pong() ->
    receive
        finished -> 
            io:format("Pong finished~n", []),
            init:stop();
        {ping, Ping_PID} -> 
            io:format("Pong received ping~n", []), 
            Ping_PID ! pong,
            pong() 
    end.

start_pong() ->
    io:format("Pong started~n", []),
    register(pong, spawn(tut17, pong, [])).

start_ping([Pong_Node]) ->
    io:format("Ping started~n", []),
    spawn(tut17, ping, [3, Pong_Node]);
start_ping(Pong_Node) ->
    start_ping([Pong_Node]).

Команды оболочки:

  • пинг: erl -noshell -sname ping -s tut17 start_ping pong@smcho
  • понг: erl -noshell -sname pong -s tut17 start_pong
person prosseek    schedule 07.03.2015
comment
Хорошо сделано. Использовать для этого init:stop/0,1 очень удобно. Прежде чем сделать это привычкой, имейте в виду, что он отключает весь узел (это именно то, что вам нужно здесь), поэтому это может быть неверным ответом для приложения OTP или почти для любого кода, который может работать вместе с другим кодом в том же узле. - person zxq9; 07.03.2015