Вопрос

Я новичок в 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.

Примечание:это не проверено, поэтому может потребоваться некоторая настройка.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top