erlang والعمليات
-
13-09-2019 - |
سؤال
أنا جديد جدا على 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.
شكرًا،
بيير. بيير
المحلول
في القوائم الخاصة بك: foreach call في الكتلة الثانية، أنت تتصل RESULT=prime:is_prime(ProcId,N)
, ، الذي يفعل receive
نتيجة لذلك. لذلك، أنت تخفيف عملية ثم انتظر حتى ينتهي حتى تفرخ العملية التالية. لهذا السبب يستغرق الأمر نفس الوقت مثل النهج الواحد الخيطي: كلا الاتجاهين، أنت تفعل واحدة فقط في وقت واحد.
بدلا من ذلك، تحتاج إلى تفرخ جميع العمليات أولا (باستخدام شيء مثل 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.
ملاحظة: هذا غير مهتم به، لذلك قد يحتاج إلى بعض التغيير والتبديل.