这个Erlang脚本打印出从3开始的奇数。 脚本运行时会逐渐变慢。我的想法是以某种方式建立起来,以制作类似于Go的筛子示例,但即使过滤掉偶数,它已经太慢了。什么导致减速以及如何解决?
#!/usr/bin/env escript
main(_) ->
print_nums().
generate(From) ->
generate(From, 2).
generate(From, N) ->
From ! N,
generate(From, N+1).
filter(Caller, P) ->
receive
N -> case (N rem P) of
0 -> filter(Caller, P);
_ -> Caller ! N,
filter(Caller, P)
end
end.
print_nums() ->
Self = self(),
FilterPid = spawn(fun() -> filter(Self, 2) end),
spawn(fun() -> generate(FilterPid) end),
print_nums_loop().
print_nums_loop() ->
receive
N -> io:format("~p~n", [N])
end,
print_nums_loop().
答案 0 :(得分:3)
这只是因为您的生产者generate
生成的消息比消费者filter
消耗的消息更快。这是标准的无聊producer-consumer问题:-)
运行这个稍微修改过的脚本版本,它会在过滤器处理过程中每隔500条消息中打印出消息队列:
#!/usr/bin/env escript
%% -*- mode: erlang -*-
%%! -smp enable -hidden
main(_) ->
Self = self(),
FilterPid = spawn(fun() -> filter(Self, 2) end),
spawn(fun() -> generate(FilterPid) end),
main_loop().
main_loop() ->
receive
N -> io:format("~B~n", [N])
end,
main_loop().
filter(Caller, P) ->
receive
N when N rem P =:= 0 -> ok;
N -> Caller ! N
end,
if N rem 500 =:= 0 -> print_queue_len();
true -> ok
end,
filter(Caller, P).
print_queue_len() ->
{message_queue_len, Len} = erlang:process_info(self(), message_queue_len),
io:format("Len:~B~n", [Len]).
generate(Filter) ->
generate(Filter, 2).
generate(Filter, N) ->
Filter ! N,
generate(Filter, N+1).
消息队列增长非常快,每收到一条消息,过滤器的速度就会慢下来。您需要让消费者控制生成器生成消息的速度(引入flow control)。就像在这段代码中一样:
#!/usr/bin/env escript
%% -*- mode: erlang -*-
%%! -smp enable -hidden
main(_) ->
Self = self(),
FilterPid = spawn(fun() -> filter(Self, 2) end),
spawn(fun() -> generate(FilterPid) end),
main_loop().
main_loop() ->
receive
N -> io:format("~B~n", [N])
end,
main_loop().
filter(Caller, P) ->
receive
{Pid, N} when N rem P =:= 0 -> ok;
{Pid, N} -> Caller ! N
end,
Pid ! ok,
filter(Caller, P).
generate(Filter) ->
generate(Filter, 2).
generate(Filter, N) ->
Filter ! {self(), N},
receive
ok -> generate(Filter, N+1)
end.