2009-12-06 5 views
1

저는 Erlang에 매우 익숙합니다. 그리고 저는 현재 Joe Armstrong의 저서 'concurrent programming'장을 읽고 있습니다. 숫자가 소수인지 (순진한 방법인지) 계산하는 프로세스 목록을 실행하려고합니다. 그러나 프로세스가없는 것처럼 코드가 실행됩니다. 두 방법 모두 동일한 지속 시간을가집니다. 내가 어디서 잘못한거야?얼랑 (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

답변

12

: 두 번째 블록에서 foreach는 호출하면 결과는 receive입니다. 따라서 프로세스를 생성하고 다음 프로세스가 생성 될 때까지 프로세스가 끝나기를 기다리고 있습니다. 이것이 단일 스레드 방식과 동일한 시간이 걸리는 이유입니다. 두 가지 방법 모두 한 번에 하나씩 만 수행하는 것입니다.

대신 모든 프로세스를 먼저 생성 (모든 PID를 추적하려면 lists:map 같은 것을 사용)하고 별도의 단계에서 결과를 기다려야합니다. 즉, 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

대단히 감사합니다! 현재 솔루션을 구현하려고합니다 :-) 표기법 (? MODULE, fun, args)이 알려지지 않았습니다. 나중에 귀하의 솔루션을 확인할 것입니다. – Pierre

+0

? MODULE은 모듈 이름에 대한 기본 제공 매크로입니다. 당신은 또한 스폰 (prime, Fun, Args)를 사용할 수 있으며, 동일 할 것입니다. – Tadmas

+1

몇 가지 방법으로 재미를내는 것이 원래대로하는 것이 더 낫습니다. 내보내기를 저장하고 실제로는 내부 용으로 만 사용되는 기능을 볼 수 있기 때문입니다. – rvirding