我应该为一个有趣的或产生多个进程生成多个进程并发送多个消息?

时间:2014-04-19 09:16:39

标签: concurrency process erlang idioms

说我有一个文件名列表(.zip)。我想同时(并行)提取文件,并为每个提取的文件并行处理它们。我目前的代码是:

start() ->
    % ..
    Pid = spawn_link(fun process/0),
    Pid ! {self(), process_stats},
    receive
        {Pid, Response} -> Response;
        {'EXIT', Pid, Reason} -> ..
    end.

process() ->
    receive
        {Pid, process_stats} ->
            Apps = get_apps(),
            Archive = spawn_link(fun archive/0),
            lists:foreach(fun({Id, AppId}) ->
                              Archive ! {self(), {extract, ?STATS_DIR++AppId++".zip", Pid}}
                          end, Apps),
            process();
        {Pid, {onextract, FilesList, Reply}} ->
            Reply ! {self(), ok},  %
            process();            
    end.

archive() ->
    receive
        {Pid, {extract, FilePath, Reply}} -> % Passing in Reply so that the receive block can send back message to the initiator. But it looks odd.
            {ok, FilesList} = zip:extract(FilePath, [{cwd, ?STATS_DIR}]),
            Pid ! {self(), {onextract, FilesList, Reply}},
            archive()
    end.

get_apps() -> ok. % returns a list of file names.

所以,我的问题是我只会产生一个进程Archive并发送多条消息。这样做会同时处理消息吗? Inside Erlang VM文件说每个调度程序有多个运行队列,所以我假设可以同时处理消息?或者为了同时处理消息,我是否必须生成多个进程并向它们发送一条消息?喜欢

        lists:foreach(fun({Id, AppId}) ->
                          Archive = spawn_link(fun archive/0),
                          Archive ! {self(), {extract, ?STATS_DIR++AppId++".zip"}}, % Here I don't have to send the Reply Pid as the receive statement is within.
                          receive
                              {Archive, {onextract, FilesList}} -> ok. % Is it ok to have nested receive blocks within a process?
                          end
                      end, Apps),

是否可以让进程拥有嵌套的接收块?哪种方法更合适?

1 个答案:

答案 0 :(得分:3)

Erlang调度程序调度进程而不是消息。如果你想同时发生一些事情,你需要多个过程。

流程内部流程是顺序的,因此archive / 0的实现正在接收消息,然后提取,然后回复,并且在递归后它接收下一条消息。

由于产生一个过程很便宜,每个文件都有一个进程没有错。无需发送消息即可开始处理,您可以在闭包中传递文件名。这里例如列表理解:

[ spawn_link(fun() -> {ok, Fs} = zip:extract(Path, Options), Pid ! {repl, Fs} end) ||
      Path <- List ],
 %% collect replies

甚至更容易使用rpc:pmap并让它完成所有工作。