2009-12-06 53 views
1

我对Erlang很新,我正在阅读Joe Armstrong的书“并发编程”一章。我试图运行一个进程列表来计算一个数字是否是一个素数(天真的方法)。但是我的代码像没有进程一样运行。两种方法的持续时间相同。我错在哪里?Erlang和进程

shell.erl:

c(prime). 

%a list of primes 
NUMS=[102950143,102950143,102950143,102950143,102950143]. 

%time start 
NOW1=now(). 
io:fwrite("Monothread~n"). 

%for each number test if it is a prime 
lists:foreach(fun(N)-> 
    RESULT=prime:is_prime(N), 
    io:fwrite("Result N=~p ~n",[RESULT]) 
    end, NUMS). 
%display the duration 
io:fwrite("Duration N=~p ~n",[timer:now_diff(now(),NOW1)/1.0e6]). 

%time start 
NOW2=now(). 
io:fwrite("Multithread~n"). 
%for each number, spawn a new process and test if it is a prime 
lists:foreach(fun(N)->ProcId = prime:start(), 
    io:fwrite("Calculating : procId=~p N=~p ~n",[ProcId,N]), 
    RESULT=prime:is_prime(ProcId,N), 
    io:fwrite("Result N=~p ~n",[RESULT]) 
    end, NUMS). 
%display the duration 
io:fwrite("Duration N=~p ~n",[timer:now_diff(now(),NOW2)/1.0e6]). 

halt(). 

文件prime.erl:

-module(prime). 
-export([start/0,is_prime/1,is_prime/2]). 
%run the forever_function 
start()->spawn(fun forever_function/0). 

%catch the queries 
forever_function()-> 
    receive 
     { From,Number} -> From! is_prime(self(),2,Number), 
     forever_function() 
    end. 

%monothreaded function 
is_prime(Number)->is_prime(self(),2,Number). 

%multithreaded function 
is_prime(ProcessID,Number)-> 
    ProcessID ! {self(),Number}, 
    receive 
     RESULT->RESULT 
    end. 

%recursive function scanning all the numbers from 2 to Number 
is_prime(ProcessID,Div,Number)-> 
    if 
     Div =:= Number -> {{number,Number},{prime,true}}; 
     Number rem Div =:= 0 -> {{number,Number},{prime,false}}; 
     true-> is_prime(ProcessID,Div+1,Number) 
    end. 

感谢,

皮埃尔

+1

这个问题可能会有用:http://stackoverflow.com/questions/1697959/why-doesnt-this-erlang-code-work – Zed 2009-12-06 16:43:50

回答

12

在你的清单:在第二块的foreach电话,你正在呼叫RESULT=prime:is_prime(ProcId,N),这是做了receive的结果。所以,你正在产生一个过程,然后等待它完成,直到你产生下一个过程。这就是为什么它需要与单线程方法相同的时间:两种方式,你只能一次做一个。相反,你需要首先产生所有的进程(使用类似lists:map的东西来跟踪所有的PID),然后在一个单独的步骤中等待结果。请注意,这意味着您必须将ProcessID ! {self(),Number}零件与receive零件分开,以便可以在第一步中完成,否则您只会产生一堆闲置的过程。

所以,像这样:

Pids = lists:map(fun(N)-> ProcId = prime:start(N), 
    io:fwrite("Calculating : procId=~p N=~p ~n",[ProcId,N]), 
    ProcId end, NUMS). 
lists:foreach(fun(ProcId) -> {N,RESULT}=prime:is_prime(ProcId), 
    io:fwrite("Result procId=~p N=~p Result=~p ~n", [ProcId,N,RESULT]) end, Pids). 

start(N)->spawn(?MODULE, forever_function, [N]). 

forever_function(Number)-> 
    Result = is_prime(self(),2,Number), 
    receive 
     { From, get_result } -> From! {Number,Result}, 
     % unnecessary since we never call this Pid again, but do it anyway :) 
     forever_function() 
     % could also add more cases here to set the number 
     % or even do a one-shot function like before 
    end. 

%multithreaded function 
is_prime(ProcessID)-> 
    ProcessID ! {self(),get_result}, 
    receive 
     RESULT->RESULT 
    end. 

注:这是未经测试,因此它可能需要一些调整。

+0

非常感谢!我目前正在尝试实现你的解决方案:-)记号spawn(?MODULE,fun,args)对我来说是未知的。我稍后会验证您的解决方案。 – Pierre 2009-12-06 16:43:57

+0

?MODULE是模块名称的内置宏,作为原子。你也可以使用spawn(prime,Fun,Args),它会是一样的。 – Tadmas 2009-12-06 18:07:29

+1

以某种方式更好地产生一种有趣的效果,因为它可以节省您的输出和可见性,这些功能仅用于内部使用。 – rvirding 2009-12-07 13:42:09