通过Joe的书,坚持第12章练习1.该练习要求人们编写一个函数 start(AnAtom,Fun),它将 AnAtom 注册为菌种(FUN)。我决定尝试一些看起来更容易的东西 - 拿完章节的'area_server'模块,然后修改它的start / 0函数:
start() ->
Pid = spawn(ex1, loop, []),
io:format("Spawned ~p~n",[Pid]),
register(area, Pid).
所以代替执行任意Fun的进程,我正在注册'loop',这是area_server模块中执行所有工作的函数:
loop() ->
receive
{From, {rectangle, Width, Ht}} ->
io:format("Computing for rectangle...~n"),
From ! {self(), Width*Ht},
loop();
{From, {square, Side}} ->
io:format("Computing for square...~n"),
From ! {self(), Side*Side},
loop();
{From, Other} ->
io:format("lolwut?~n"),
From ! {self(), {error, Other}},
loop()
end.
似乎工作正常:
1> c("ex1.erl").
{ok,ex1}
2> ex1:start().
Spawned <0.68.0>
true
3>
3> area ! {self(), hi}.
lolwut?
{<0.61.0>,hi}
4> flush().
Shell got {<0.68.0>,{error,hi}}
ok
5> area ! {self(), {square, 7}}.
Computing for square...
{<0.61.0>,{square,7}}
6> flush().
Shell got {<0.68.0>,49}
ok
当我试图测试多个进程可以与已注册的“服务器”通信时,事情变得很糟糕。 (CTRL-G,s,c 2)
我在一个新的shell中,与第一个一起运行 - 但是当我从这个新shell发送消息到我的'area'注册过程时,发生了一些令人讨厌的事情 - 当查询process_info(whereis(area))时,进程离开这个状态:
{current_function,{ex1,loop,0}},
{initial_call,{ex1,loop,0}},
到这一个:
{current_function,{io,execute_request,2}},
{initial_call,{ex1,loop,0}},
当消息队列开始增长时,消息未被处理。挂在模块 io 中,呵呵!在io操作上有什么东西被阻止了?显然,这个过程从我的ex1:loop / 0移到了io:execute_request / 2(无论是什么)......是我的傻打印导致了这个问题吗?
答案 0 :(得分:1)
您的流程正在按照您的期望执行,但处理谁在何时控制STDOUT 除外。是的,这可能会导致shell中出现奇怪的表现行为。
所以让我们尝试类似这样的,不用任何暗示去STDOUT的IO命令,看看会发生什么。下面是一个shell会话,我定义了一个累积消息的循环,直到我要求它向我发送它已经积累的消息。我们可以从这个例子中看到(这个例子不会挂在允许与单个输出资源对话的人身上)进程按预期运行。
需要注意的一点是你不需要多个shell来与多个进程交谈。
注意shell中flush/0
的返回值 - 它是一个特殊的shell命令,它将shell的邮箱转储到STDOUT。
Eshell V9.0 (abort with ^G)
1> Loop =
1> fun L(History) ->
1> receive
1> halt ->
1> exit(normal);
1> {Sender, history} ->
1> Sender ! History,
1> L([]);
1> Message ->
1> NewHistory = [Message | History],
1> L(NewHistory)
1> end
1> end.
#Fun<erl_eval.30.87737649>
2> {Pid1, Ref1} = spawn_monitor(fun() -> Loop([]) end).
{<0.64.0>,#Ref<0.1663562856.2369257474.102541>}
3> {Pid2, Ref2} = spawn_monitor(fun() -> Loop([]) end).
{<0.66.0>,#Ref<0.1663562856.2369257474.102546>}
4> Pid1 ! "blah".
"blah"
5> Pid1 ! "blee".
"blee"
6> Pid1 ! {self(), history}.
{<0.61.0>,history}
7> flush().
Shell got ["blee","blah"]
ok
8> Pid1 ! "Message from shell 1".
"Message from shell 1"
9> Pid2 ! "Message from shell 1".
"Message from shell 1"
10>
User switch command
--> s
--> j
1 {shell,start,[init]}
2* {shell,start,[]}
--> c 2
Eshell V9.0 (abort with ^G)
1> Shell1_Pid1 = pid(0,64,0).
<0.64.0>
2> Shell1_Pid2 = pid(0,66,0).
<0.66.0>
3> Shell1_Pid1 ! "Message from shell 2".
"Message from shell 2"
4> Shell1_Pid2 ! "Another message from shell 2".
"Another message from shell 2"
5> Shell1_Pid1 ! {self(), history}.
{<0.77.0>,history}
6> flush().
Shell got ["Message from shell 2","Message from shell 1"]
ok
7>
User switch command
--> c 1
11> Pid2 ! {self(), history}.
{<0.61.0>,history}
12> flush().
Shell got ["Another message from shell 2","Message from shell 1"]
ok