Erlang und Prozesse
-
13-09-2019 - |
Frage
Ich bin sehr neu in Erlang und ich bin derzeit Joe Armstrong Buch, Kapitel ‚Concurrent Programming‘ zu lesen. Ich versuche, eine Liste der Prozesse zu laufen zu berechnen, wenn eine Zahl eine Primzahl (naive Methode) ist. Aber mein Code ausgeführt wird, als gäbe es keine Prozesse war. Beide Methoden haben die gleiche Dauer. Wo bin ich falsch?
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().
Datei 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.
Danke,
Pierre
Lösung
In Ihren Listen: foreach Anruf im zweiten Block, die Sie anrufen RESULT=prime:is_prime(ProcId,N)
, die eine receive
für das Ergebnis tun. Sie sind also ein Prozess Laichen und dann warten, bis es beendet wird, bis der nächste Prozess erzeugen. Deshalb ist es die gleiche Menge an Zeit wie der Single-Thread-Ansatz nimmt. In beiden Richtungen, sie ist nur einen nach dem anderes zu tun
Stattdessen müssen Sie zunächst alle Prozesse zum Laichen (so etwas wie lists:map
mit behalten den Überblick über alle PIDs) und dann die Ergebnisse in einem separaten Schritt warten. Beachten Sie, dass heißt, Sie müssen werden das ProcessID ! {self(),Number}
Teil aus dem receive
Teil aufgeteilt, so dass in der ersten Stufe durchgeführt werden, sonst sind Sie nur ein paar Leer Prozesse Laichen.
Also, so etwas wie:
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.
. Hinweis: dies ist nicht getestet, so kann es einige Optimierungen benötigen