ska*_*tek 5 parallel-processing erlang
在编程Erlang书的"编程多核CPU"一章中,Joe Armstrong给出了一个很好的并行化map函数的例子:
pmap(F, L) ->
S = self(),
%% make_ref() returns a unique reference
%% we'll match on this later
Ref = erlang:make_ref(),
Pids = map(fun(I) ->
spawn(fun() -> do_f(S, Ref, F, I) end)
end, L),
%% gather the results
gather(Pids, Ref).
do_f(Parent, Ref, F, I) ->
Parent ! {self(), Ref, (catch F(I))}.
gather([Pid|T], Ref) ->
receive
{Pid, Ref, Ret} -> [Ret|gather(T, Ref)]
end;
gather([], _) ->
[].
Run Code Online (Sandbox Code Playgroud)
它工作得很好,但我相信它有一个瓶颈,导致它在100,000多个元素的列表上工作得非常慢.
gather()
执行该功能时,它开始匹配列表中的第Pid
一个Pids
与主进程邮箱中的消息.但是如果邮箱中最旧的邮件不是来自这个Pid
呢?然后它会尝试所有其他消息,直到找到匹配项.话虽如此,有一定的可能性,在执行gather()
函数时,我们必须循环遍历所有邮箱消息,以找到与Pid
我们从Pids
列表中获取的匹配项.对于大小为N的列表,这是N*N最坏情况.
我甚至设法证明了这个瓶颈的存在:
gather([Pid|T], Ref) ->
receive
{Pid, Ref, Ret} -> [Ret|gather(T, Ref)];
%% Here it is:
Other -> io:format("The oldest message in the mailbox (~w) did not match with Pid ~w~n", [Other,Pid])
end;
Run Code Online (Sandbox Code Playgroud)
我怎样才能避免这个瓶颈?