EMZETT.
Login

Kurz: Erlang-Prozesse sind extrem leichtgewichtig (Hunderttausende sind normal) und teilen keinen Speicher. Sie kommunizieren per Nachricht mit ! (senden) und receive (empfangen):

Teil des Kurses Erlang

Kapitel 5 von 8 im Kurs Erlang. Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Prozesse starten und Nachrichten senden

Erlang-Prozesse sind extrem leichtgewichtig (Hunderttausende sind normal) und teilen keinen Speicher. Sie kommunizieren per Nachricht mit ! (senden) und receive (empfangen):

echo() ->
    receive
        {From, Nachricht} ->
            From ! {echo, Nachricht},
            echo();
        stop ->
            ok
    end.
 
main(_) ->
    Pid = spawn(fun echo/0),
    Pid ! {self(), hallo},
    receive
        {echo, Antwort} -> io:format("Antwort: ~p~n", [Antwort])
    after 1000 -> io:format("Timeout~n")
    end,
    Pid ! {self(), welt},
    receive
        {echo, A2} -> io:format("Antwort: ~p~n", [A2])
    end,
    Pid ! stop,
    timer:sleep(50),
    io:format("lebt noch: ~p~n", [is_process_alive(Pid)]).

Ausgabe:

Antwort: hallo
Antwort: welt
lebt noch: false

Zustand in Prozessen

Ein Prozess hält Zustand in den Argumenten seiner Schleife:

zaehler(N) ->
    receive
        erhoehe -> zaehler(N + 1);
        {abfragen, From} -> From ! {stand, N}, zaehler(N);
        stop -> ok
    end.
 
main(_) ->
    Z = spawn(fun() -> zaehler(0) end),
    [Z ! erhoehe || _ <- lists:seq(1, 5)],
    Z ! {abfragen, self()},
    receive {stand, Stand} -> io:format("Stand: ~p~n", [Stand]) end,
    Z ! stop,
 
    Eltern = self(),
    Arbeiter = [spawn(fun() -> Eltern ! {ergebnis, I, I * I} end) || I <- lists:seq(1, 5)],
    Ergebnisse = [receive {ergebnis, I, Q} -> {I, Q} end || I <- lists:seq(1, length(Arbeiter))],
    io:format("~p~n", [lists:sort(Ergebnisse)]),
 
    Viele = [spawn(fun() -> receive stop -> ok end end) || _ <- lists:seq(1, 10000)],
    io:format("~p Prozesse gestartet~n", [length(Viele)]),
    [P ! stop || P <- Viele],
    ok.

Ausgabe:

Stand: 5
[{1,1},{2,4},{3,9},{4,16},{5,25}]
10000 Prozesse gestartet

Verknüpfung, Monitore und Fehler

Prozesse können sich gegenseitig überwachen. Das ist die Grundlage der Fehlertoleranz:

main(_) ->
    logger:set_primary_config(level, none),     % Absturzberichte unterdrücken
    {Pid, Ref} = spawn_monitor(fun() -> exit(kaputt) end),
    receive
        {'DOWN', Ref, process, Pid, Grund} -> io:format("Prozess endete: ~p~n", [Grund])
    end,
 
    process_flag(trap_exit, true),
    Kind = spawn_link(fun() -> 1 / hd([0]) end),
    receive
        {'EXIT', Kind, {badarith, _}} -> io:format("Kind: badarith~n");
        {'EXIT', Kind, Anders} -> io:format("Kind: ~p~n", [Anders])
    end,
 
    {P2, R2} = spawn_monitor(fun() -> ok end),
    receive {'DOWN', R2, process, P2, normal} -> io:format("normal beendet~n") end,
 
    register(meinprozess, spawn(fun() -> receive {Von, ping} -> Von ! pong end end)),
    meinprozess ! {self(), ping},
    receive pong -> io:format("pong von registriertem Namen~n") end,
    io:format("~p~n", [whereis(unbekannt)]).

Ausgabe:

Prozess endete: kaputt
Kind: badarith
normal beendet
pong von registriertem Namen
undefined

Merke

  • spawn startet Prozesse, ! sendet, receive empfängt (mit after als Timeout)
  • Prozesse teilen keinen Speicher; Zustand lebt in der Schleife des Prozesses
  • spawn_link, spawn_monitor und trap_exit überwachen andere Prozesse
  • register/2 gibt Prozessen Namen

Übungsaufgabe

Schreibe einen Prozess, der Zahlen addiert und die Summe auf Anfrage zurückschickt.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Rekursion, Strings und Binaries

Weiter: OTP: gen_server und Supervisor

Alle Kapitel: Erlang im Überblick