Erlang (język programowania)

Z Wikipedii, wolnej encyklopedii
Erlang
Logo języka Erlang
Logo języka
Pojawienie się

1986

Paradygmat

wieloparadygmatowy: funkcyjny, współbieżny

Typowanie

dynamiczne (silne)

Aktualna wersja stabilna

26.2.2
(8 lutego 2024) [±]

Twórca

Ericsson

Licencja

Apache License 2.0[1]

Platforma sprzętowa

wieloplatformowy

Platforma systemowa

wieloplatformowy

Strona internetowa

Erlangjęzyk programowania zaprojektowany z myślą o zastosowaniach współbieżnych, a także środowisko uruchomieniowe dla aplikacji w nim napisanych. Sekwencyjny podzbiór Erlanga jest językiem funkcyjnym z wartościowaniem zachłannym, jednokrotnym przypisaniem oraz dynamicznym typowaniem. Część współbieżna bazuje na teoretycznym modelu znanym jako Actor model[potrzebny przypis]. Język został zaprojektowany pod kątem tworzenia rozproszonych systemów wymagających długotrwałej pracy oraz odporności na awarie. Obsługuje mechanizm hot-swappingu pozwalający na aktualizację kodu aplikacji bez jej zatrzymywania.

Język został zaprojektowany przez Joe Armstronga w 1986 roku pracującego w firmie Ericsson. Początkowo był własnościowym narzędziem tej firmy, lecz w roku 1998 wraz z implementacją i bibliotekami, stał się wolnym oprogramowaniem. Nazwa Erlang została nadana na cześć A. K. Erlanga[potrzebny przypis], choć często bywa również interpretowana jako „Ericsson Language”.

Historia[edytuj | edytuj kod]

Między 1982 a 1986 rokiem w laboratoriach firmy Ericsson prowadzone były badania nad przydatnością poszczególnych istniejących wówczas języków programowania pod kątem tworzenia aplikacji współbieżnych na potrzeby telekomunikacji, które wymagały długotrwałej, bezawaryjnej pracy przy dużej liczbie wątków[2]. Analizowano cechy każdego języka, identyfikując potencjalne problemy, jakie mogły one powodować. Mimo stopniowego zawężania zbioru rozpatrywanych języków, ustalono, że żaden z nich nie spełnia wymagań firmy, dlatego zdecydowano się na zaprojektowanie zupełnie nowego od podstaw.

Erlanga stworzył Joe Armstrong, wzorując się na języku Prolog i pisząc w nim pierwszy interpreter[3]. Był on testowany przez Ericsson oraz wybrane firmy zewnętrzne. W 1990 roku język został pokazany publicznie na konferencji ISS'90, co zaowocowało wzrostem liczby użytkowników[2][3]. Pierwsza implementacja języka była mało wydajna, dlatego już w latach 80. rozpoczęto prace nad jej szybszym następcą[potrzebny przypis]. Ostateczne jej udostępnienie miało miejsce w roku 1991. Rok później ukazała się pierwsza książka poświęcona Erlangowi, a w 1993 Ericsson wydzielił samodzielny dział zajmujący się rozwojem i dystrybucją systemu oraz narzędzi do niego[potrzebny przypis].

W 1998 roku Ericsson zademonstrował switch AXD301 z oprogramowaniem zawierającym milion linii kodu w Erlangu, który osiągnął wskaźnik niezawodności 99,9999999%[potrzebny przypis], co oznaczało, że w ciągu roku system mógł mieć co najwyżej 0,0315 sekundy przestoju spowodowanego awarią. Niedługo później firma Ericsson zabroniła swoim oddziałom wykorzystywania Erlanga w nowych produktach z uwagi na jego własnościowy charakter. Stało się to przyczyną konfliktu między Ericssonem a Armstrongiem, który wraz z zespołem opuścił firmę[3]. Pod koniec tego samego roku kod implementacji Erlanga został otwarty i udostępniony jako wolne oprogramowanie. Zakaz został w późniejszych latach cofnięty, a Armstrong powrócił do pracy w Ericssonie w 2004 roku.

W 2007 roku w Erlangu pojawiła się obsługa symetrycznej wieloprocesorowości.

Założenia[edytuj | edytuj kod]

W przetwarzaniu współbieżnym największe zagrożenie dla bezpieczeństwa systemu stanowi globalny stan, który może zostać w dowolnej chwili zmieniony przez dowolny wątek. Klasyczne mechanizmy synchronizacji, takie jak muteksy i semafory, są skomplikowane w użyciu, a analiza większych systemów z nich korzystających jest nieefektywna[potrzebny przypis]. Zamiast nich, mechanizm współbieżności w Erlangu opracowano na bazie matematycznego modelu znanego jako Actor model, który został zaprezentowany w 1975 roku. W celu eliminacji skutków ubocznych część sekwencyjną Erlanga zaprojektowano jako język funkcyjny. Ponieważ wszystkie funkcje są z założenia bezstanowe, wykonywane równolegle zadania nie współdzielą między sobą żadnych danych a zatem nie mogą przypadkowo wpłynąć na przebieg innego zadania, co mogłoby zakończyć się awarią. Z tego powodu w Erlangu nie istnieje pojęcie wątku – wszystkie zadania są procesami.

Środowisko uruchomieniowe Erlanga zostało zaprojektowane, aby efektywnie radzić sobie z obsługą dużej liczby procesów. Wynika to nie tylko z chęci udostępnienia aplikacjom erlangowym większych zasobów, lecz także z faktu, iż konstrukcja języka zachęca programistę do tworzenia procesów w miejscu, gdzie w innych językach stosowane były mechanizmy sekwencyjne. Erlang potrafi wykorzystywać możliwości maszyn wieloprocesorowych, a także skalować aplikację na środowisko sieciowe w sposób przezroczysty – model współbieżności sprawia, że z punktu widzenia procesu nie ma różnicy między komunikacją z innym procesem uruchomionym na tym samym a na odległym węźle.

Długodziałające systemy są narażone na różnego rodzaju awarie, związane zarówno z błędami w oprogramowaniu, jak i problemami sprzętowymi. Istotnym celem Erlanga było zapewnienie możliwości obsługi sytuacji krytycznych już na poziomie języka. Środowisko uruchomieniowe raportuje wszystkie błędy jako wyjątki. Procesy mogą śledzić się nawzajem, dzięki czemu możliwe jest wykrycie awarii jednego z nich i jego ponowne uruchomienie. Dodatkowo, aby unikać przestojów, Erlang udostępnia mechanizm hot-swappingu umożliwiający aktualizację aplikacji bez jej wyłączania.

Paradygmaty programowania[edytuj | edytuj kod]

Programowanie funkcyjne[edytuj | edytuj kod]

Silnię można zaimplementować w następujący sposób:

-module(fact).
-export([fac/1]).

fac(0) -> 1;
fac(N) when N > 0 -> N * fac(N-1).

Poniżej jest implementacja algorytmu Quicksort:

%% quicksort:qsort(List)
%% Sort a list of items
-module(quicksort).
-export([qsort/1]).

qsort([]) -> [];
qsort([Pivot|Rest]) ->
    qsort([ X || X <- Rest, X < Pivot]) ++ [Pivot] ++ qsort([ Y || Y <- Rest, Y >= Pivot]).

Powyższy przykład wywołuje rekursywnie funkcję qsort, dopóki nie ma już więcej elementów do posortowania. Wyrażenie [ X || X <- Rest, X < Pivot] można przeczytać jako "Dla wszystkich X należących do Rest, takich że X jest mniejsze od Pivot", co bardzo upraszcza obsługę list.

Model współbieżności[edytuj | edytuj kod]

Główną siłą Erlanga jest wsparcie dla współbieżności. Ma on mały, lecz bardzo potężny zbiór niskopoziomowych funkcji do tworzenia procesów i komunikacji między nimi. Procesy są podstawowymi elementami w strukturze aplikacji napisanych w Erlangu. Należy zaznaczyć, iż Erlang nie używa ani procesów systemu operacyjnego, ani wątków. Procesy Erlanga są lekkimi wątkami podobnymi do zielonych wątków. Dzięki temu można utworzyć ich bardzo dużo bez zmniejszania wydajności (przeprowadzano testy wydajnościowe z 20 milionami procesów[4]).

Komunikacja pomiędzy procesami w Erlangu odbywa się poprzez asynchroniczne kanały (procesy nie współdzielą żadnych zmiennych) – system wymiany wiadomości: każdy proces w Erlangu ma skrzynkę (ang. mailbox), w której są przechowywane wiadomości wysłane przez inne procesy, dopóki nie zostaną odczytane. Proces Erlanga następnie używa instrukcji receive do pobrania wiadomości. Odbieranie wiadomości odbywa się przez mechanizm dopasowania wzorca. Po odczytaniu wiadomości proces Erlanga wraca do wykonywania. Dowolna struktura w Erlangu może zostać użyta jako wiadomość – prymitywy (liczby całkowite, zmiennoprzecinkowe, znaki, atomy), krotki, listy, a nawet funkcje.

Przykładowy kod:

 Pid = spawn(Mod, Func, Args)       % uruchamia funkcje Func jako nowy proces
 Pid = spawn(Node, Mod, Func, Args) % uruchamia funkcje Func na zdalnym węźle Node

 Pid ! a_message      % wysyła wiadomość do procesu (asynchronicznie)

 receive       % odbiera wiadomość wysłaną do tego procesu
   a_message -> do_something;
   {data, Data_content} -> do_something_else(); % To jest 2-ka składają się z atomu i pewnych danych
   {hello, Text} -> io:format("Got hello message: ~s", [Text]);
   {goodbye, Text} -> io:format("Got goodbye message: ~s", [Text])
 end.

Prosty serwer można zaimplementować na bazie prostej pętli:

-export([start/1, loop/1, net_state/2, get_state/1]).

start(S) ->
  Pid = spawn(mymodule, loop, [S]). % uruchom proces serwera

% kod wykonywany po stronie serwera

loop(State) ->
  receive
    {mymodule, get_state, Pid, Ref} -> Pid ! {mymodule, state, Ref, State}, loop(State);
    {mymodule, new_state, Pid, Ref, State2} -> Pid ! {mymodule, ok, Ref}, loop(State2);
    upgrade -> mymodule:loop(State);
    M -> io:format("Niezrozumiala wiadomosc: ~p~n", [M]), loop(State)
    after 1000 -> io:format("Nic sie nie dzieje~n"), loop(State)
  end.

% Kod wykonywany po stronie klienta

new_state(Pid, X) ->
  Ref = make_ref(), % stworzy unikalna wartosc, aby nie pomylic sie przy odbiorze
  Pid ! {mymodule, new_state, self(), Ref, X},  % wyslij wiadomosc
  rec1(Ref). % zacznij odbierac, potencjalnie usuwajac stare (po timeoutach) wiadomosci

rec1(Ref) ->
  receive
    {mymodule, ok, Ref, OldState} -> ok  % czekaj na dokladnie nasza wiadomosc, jesli jej nie ma, to:
    {mymodule, ok, OtherRef, _OldState} -> rec1(Ref); % usun stare wiadomosci z kolejki i czekaj nadal na odbior, jesli ich nie ma, to:
    after 1000 -> throw (timeout) % w przypadku timeoutu, zglos wyjatek
  end.

...

(make_ref/0 zwraca unikalną wartość, dzięki czemu nawet przy przekroczeniu czasu oczekiwania i przyjściu starej wiadomości selektywny receive nie pomyli nowej odpowiedzi ze starą)

W większości wypadków korzysta się z wytycznych projektowych OTP, wśród których istnieje zachowanie (behaviour) gen_server, ułatwiające pisanie wydajnych i bezpiecznych serwerów.

W Erlangu jest wbudowane wsparcie dla procesów rozproszonych. Proces może zostać utworzony na zdalnym węźle, a komunikacja z nim jest przezroczysta (tzn. komunikację ze zdalnym procesem odbywa się w dokładnie taki sam sposób jak z procesem lokalnym).

Współbieżność wspiera obsługę błędów w Erlangu. Kiedy proces się zepsuje, kończy się i wysyła wiadomość do procesu kontrolnego, który może podjąć odpowiednią akcje. Ten sposób naprawy błędów ułatwia obsługę i redukuje złożoność kodu.

Dystrybucja[edytuj | edytuj kod]

Erlang został upubliczniony wraz z kodem źródłowym przez firmę Ericsson, aby zapewnić jego niezależność od pojedynczej firmy i zwiększyć popularność języka. Język jest rozprowadzany razem z bibliotekami (m.in. implementacją CORBA, SNMP, HTTP, FTP, TCP/IP, IIOP) oraz rozproszoną bazą danych czasu rzeczywistego (Mnesia) całość jest znana jako Open Telecom Platform (OTP), ponieważ jest najczęściej wykorzystywana w zastosowaniach telekomunikacyjnych. Ericsson i kilka innych firm oferują komercyjną pomoc dla Erlanga.

Ważnym elementem OTP są gotowe wzorce projektowe (tzw. zachowania – behaviors) do tworzenia aplikacji, systemów nadzoru procesów, czy serwerów i mechanizmów przetwarzania zdarzeń.

Po uwolnieniu źródeł w 1998, jest coraz chętniej wykorzystywany w zastosowaniach współbieżnych (oprogramowanie serwerowe) przez duże światowe koncerny[5]. Największym użytkownikiem jest Ericsson, zaś wśród innych można wymienić Facebook, T-Mobile czy Goldman Sachs. Nie jest to jednak język ogólnego przeznaczenia – używający go programiści zwracają uwagę na wiele niedoskonałości w innych obszarach zastosowań[6].

Erlang jest aktywnie rozwijany z regularnymi wydaniami. Najnowsze wydanie (OTP 23.2) dostępne jest dla systemów Unix oraz Microsoft Windows[7]

Dostępny jest również interfejs niskopoziomowy dla języków C i Java. Istnieją również biblioteki ułatwiające obsługę protokołu i wartości erlangowych z poziomu C[8] czy Pythona[9].

Corocznie odbywa się kilka konferencji poświęconych Erlangowi: Code BEAM w San Francisco i Londynie, Erlang/OTP User Conference w Sztokholmie, ACM SIGPLAN Erlang Workshop w Edynburgu.

Przypisy[edytuj | edytuj kod]

  1. About Erlang, www.erlang.org [dostęp 2019-06-23].
  2. a b History of Erlang. An Erlang Course. [dostęp 2010-09-18]. (ang.).
  3. a b c Joe Armstrong: A History of Erlang. [dostęp 2010-09-18]. (ang.).
  4. stress-testing erlang. Grupa dyskusyjna comp.lang.functional. [dostęp 2011-08-28]. (ang.).
  5. Who uses Erlang for product development?. Erlang FAQ. [dostęp 2011-11-19]. (ang.).
  6. The Trouble with Erlang (or Erlang is a ghetto). Unlimited Novelty, 2011-07-26. [dostęp 2011-11-19]. (ang.).
  7. Erlang/OTP 20.3 has been released. www.erlang.org, 2018-03-14. [dostęp 2018-03-21]. (ang.).
  8. Dryverl. dryverl.ow2.org. [zarchiwizowane z tego adresu (2010-07-16)].Erlang-to-C binding "assembly language" (ang.)
  9. Pytherl na Bitbucket. [dostęp 2010-09-18]. [zarchiwizowane z tego adresu (2015-09-18)].

Linki zewnętrzne[edytuj | edytuj kod]