从命令行在 Erlang 代码中执行并发示例
Executing concurrent example in Erlang code from command line
我正在测试 Getting Started with Erlang User's Guide 并发编程部分中的代码。
在 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]).
从 ping 和 pong 过程中,我可以调用 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
- 来自 pong 节点:
erl -noshell -sname pong -s tut17 start_pong -s init stop
但是,当 pong
结束时没有打印任何内容时,我从 ping
收到了这个错误报告。
=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方式,使用命令行,每个进程不等待对方响应,而是在一段时间后停止。
可能出了什么问题?
当使用 -s
开关时,来自命令行的参数被接收为原子列表,而当使用 -run
开关时,接收到的参数是字符串列表。考虑到这一点,让我们仔细想想会发生什么......
这个命令是从shell发出的:
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 shell 和系统 shell 的舒适你可以添加一个子句到 start_ping/1
:
start_ping([Pong_Node]) ->
spawn(tut17, ping, [3, Pong_Node]);
start_ping(Pong_Node) ->
start_ping([Pong_Node]).
需要进行一些更改。
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();
然后我可以从 shell 命令中删除 -s init stop
:erl -noshell -sname ping -s tut17 start_ping pong@smcho
.
执行顺序
应在调用 Ping 之前调用 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", []),
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]).
shell 命令:
- ping:
erl -noshell -sname ping -s tut17 start_ping pong@smcho
- 乒乓球:
erl -noshell -sname pong -s tut17 start_pong
我正在测试 Getting Started with Erlang User's Guide 并发编程部分中的代码。
在 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]).
从 ping 和 pong 过程中,我可以调用 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
- 来自 pong 节点:
erl -noshell -sname pong -s tut17 start_pong -s init stop
但是,当 pong
结束时没有打印任何内容时,我从 ping
收到了这个错误报告。
=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方式,使用命令行,每个进程不等待对方响应,而是在一段时间后停止。 可能出了什么问题?
当使用 -s
开关时,来自命令行的参数被接收为原子列表,而当使用 -run
开关时,接收到的参数是字符串列表。考虑到这一点,让我们仔细想想会发生什么......
这个命令是从shell发出的:
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 shell 和系统 shell 的舒适你可以添加一个子句到 start_ping/1
:
start_ping([Pong_Node]) ->
spawn(tut17, ping, [3, Pong_Node]);
start_ping(Pong_Node) ->
start_ping([Pong_Node]).
需要进行一些更改。
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();
然后我可以从 shell 命令中删除 -s init stop
:erl -noshell -sname ping -s tut17 start_ping pong@smcho
.
执行顺序
应在调用 Ping 之前调用 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", []),
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]).
shell 命令:
- ping:
erl -noshell -sname ping -s tut17 start_ping pong@smcho
- 乒乓球:
erl -noshell -sname pong -s tut17 start_pong