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

War es hilfreich?

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top