Эрланг и процессы
-
13-09-2019 - |
Вопрос
Я новичок в Erlang и сейчас читаю книгу Джо Армстронга, главу «параллельное программирование».Я пытаюсь запустить список процессов, чтобы вычислить, является ли число простым (наивный метод).Но мой код работает так, как будто процессов нет.Оба метода имеют одинаковую продолжительность.Где я ошибаюсь?
оболочка.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.
Спасибо,
Пьер
Решение
В ваших списках: вызов 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.
Примечание:это не проверено, поэтому может потребоваться некоторая настройка.