Erlang et processus
-
13-09-2019 - |
Question
Je suis très nouveau pour Erlang et je lis actuellement le livre de Joe Armstrong, « programmation concurrente » chapitre. Je suis en train d'exécuter une liste de processus pour calculer si un nombre est un nombre premier (méthode naïve). Mais mon code fonctionne comme s'il n'y avait pas de processus. Les deux méthodes ont la même durée. Où suis-je tort?
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().
fichier 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.
Merci,
Pierre
La solution
Dans vos listes: appel foreach dans le deuxième bloc, vous appelez RESULT=prime:is_prime(ProcId,N)
, qui est en train de faire un receive
pour le résultat. Donc, vous fraye un processus et puis d'attendre qu'elle se termine jusqu'à ce que vous frayer le processus suivant. Voilà pourquoi il prend la même quantité de temps que l'approche mono-thread. Dans les deux sens, vous faites une seule à la fois
, vous avez besoin au lieu de reproduire tous les processus d'abord (en utilisant quelque chose comme lists:map
de garder une trace de tous les PIDS), puis attendre les résultats dans une étape séparée. Notez que signifie que vous devrez diviser la partie ProcessID ! {self(),Number}
de la partie receive
afin que peut être fait dans la première étape, sinon vous fraie juste un tas de processus inactifs.
Alors, quelque chose comme:
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.
Note:. Ce n'est pas testé, donc il peut avoir besoin de quelques ajustements