Jun 2009

Parallele Funktionen Höherer Ordnung - pmap

Erlangs leichtgewichtiges Prozessmodell ermöglicht die Erzeugung von mehreren tausend Prozessen. Aus diesen Grund lassen sich in Erlang Programme entwickelt, die gut mit der Anzahl der Kerne auf einem Multicore Prozessor skalieren. Eine tolle Sache, wenn wir davon ausgehen können, dass Multicore Prozessoren der Zukunft dutzende oder sogar hunderte Kerne haben, denn so profitieren unsere Erlang Programme ohne weiteres Zutun davon.

Beispiel:

Die Funktion pmap(Fun, Liste) -- in Anlehnung an die sequentielle High Order Funktion map -- wertet alle Elemente der Liste parallel aus. Dazu wird für jedes Element der Liste ein eigener Prozess erzeugt; dieser Prozess führt dann Fun(Element) aus. Hat Fun das Ergebnis erarbeitet, wird dieses dem „Vaterprozess“ in die Mailbox gestellt. Dieser sammelt alle Ergebnisse in der Reihenfolge der Originalliste auf und liefert als Ergebnis eine Liste; das Resultat von pmap.

-module(pm).
-export([pmap/2]).

pmap(Fun, Liste) ->
  Pid = self(),
  Ref=erlang:make_ref(),
  Pids=lists:map(fun(Element) ->
     spawn(fun() -> do_fun(Pid, Ref, Fun, Element) end) end,
  sammel(Pids, Ref).

do_fun(VaterPid, Ref, Fun, Element) ->
  VaterPid ! {self(), Ref, catch(Fun(Element))}.

sammel([Pid | T], Ref) ->
  receive
    {Pid, Ref, Ergebnis} -> [Ergebnis | sammel(T, Ref)]
  end;
sammel([], _) -> [].

Folgendes Beispiel berechnet die Fakultät parallel für alle Elemente einer Liste von 1000 Zufallswerten zwischen 0 und 30.

test_pmap(Max) ->
  List = lists:seq(1, Max),
  TestData = lists:map(fun(_) -> random:uniform(30) end, List),
  pm:pmap(fun fac/1, TestData).


> test_pmap(1000).

Hinweise:
Da mit jedem Listenelement ein neuer Prozess erzeugt wird, sollte man bei grossen Listen ein wenig aufpassen.

Damit Prozesse von Multicore Prozessoren profitieren, sollten sie
(a) keine Seiteneffekte haben,
(b) möglichst rechenintensive Aufgaben durchführen und
(c) Meldungen, die sie versenden, möglichst klein sein .