Erlang OTP: Programmering av distribuerade och feltoleranta system · Lektion

Implementera GenServer-behavior

Lär er implementera en GenServer, hantera tillstånd och behandla synkrona och asynkrona anrop – grunden för de flesta Erlang-komponenter.

Lektion 2 av 411 steg

Implementera GenServer-behavior är en gratis lektion i Erlang OTP: Programmering av distribuerade och feltoleranta system på CoddyKit. Detta är lektion 2 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Erlang OTP: Programmering av distribuerade och feltoleranta system, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Erlang OTP: Programmering av distribuerade och feltoleranta system innehåller totalt 4 lektioner.

Vad är en GenServer?

Välkommen tillbaka! I den förra lektionen lärde vi oss om Erlangs OTP-behaviors. Ett av de viktigaste är GenServer.

  • En GenServer är en generisk server som hanterar begäranden.
  • Den hanterar internt tillstånd och bearbetar meddelanden sekventiellt.
  • Se den som ett standardiserat sätt att bygga tillförlitliga och feltoleranta serverprocesser i Erlang.

Den utgör grunden för många Erlang-applikationer.

GenServers kärna: callbacks

För att implementera en GenServer definierar du en modul som exporterar specifika callback-funktioner. Dessa funktioner anropas av behavioren gen_server i olika steg.

  • init/1: Initierar serverns tillstånd.
  • handle_call/3: Hanterar synkrona klientbegäranden (förväntar sig ett svar).
  • handle_cast/2: Hanterar asynkrona klientbegäranden (skicka och glöm).
  • terminate/2: Stänger ner resurser när servern stoppas.
  • code_change/3: Hanterar koduppgraderingar under drift.

I den här lektionen fokuserar vi på init, handle_call och handle_cast.

Initiera tillstånd med `init/1`

Varje GenServer börjar med att initiera sitt tillstånd. Detta görs i callback-funktionen init/1.

Den tar ett argument (vanligtvis en lista med argument som skickas vid uppstart) och ska returnera {ok, State}, där State är de initiala data som din GenServer ska hantera.

Här är en grundläggande init-funktion:

-module(my_counter).
-behaviour(gen_server).
-export([init/1]).

init([]) ->
    io:format("Counter initialized with state 0.~n"),
    {ok, 0}.

Starta en GenServer-process

För att få vår GenServer att köra måste vi starta den. Det vanligaste sättet är att använda gen_server:start_link/3 eller gen_server:start_link/4. Vi lägger till en start_link/0-funktion i vår modul.

Funktionen start_link skapar en ny Erlang-process och länkar den till den anropande processen, vilket gör den till en del av ett övervakningsträd (mer om detta senare!).

-module(my_counter).
-behaviour(gen_server).
-export([start_link/0, init/1]).

start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

init([]) ->
    io:format("Counter process started!~n"),
    {ok, 0}.

Synkrona anrop: `handle_call`

När en klient behöver ett svar från servern gör den ett synkront anrop med gen_server:call/2 eller gen_server:call/3.

GenServer hanterar dessa begäranden i sin callback handle_call/3. Funktionen tar tre argument:

  • Request: Meddelandet från klienten.
  • From: Den sändande processens ID (Pid) och en tagg.
  • State: GenServers aktuella interna tillstånd.

Den returnerar vanligtvis {reply, Reply, NewState}.

Implementera `handle_call` (räknare)

Vi lägger till en increment-funktion i vår räknare. Detta blir ett synkront anrop, vilket innebär att klienten väntar på det nya värdet.

Prova att köra den här koden. Kompilera den först (c(my_counter).) och starta den sedan (my_counter:start_link().). Därefter kan du anropa my_counter:increment(). för att se räknaren öka.

-module(my_counter).
-behaviour(gen_server).
-export([start_link/0, increment/0, get_count/0]).
-export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3]).

start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

increment() ->
    gen_server:call(?MODULE, increment).

get_count() ->
    gen_server:call(?MODULE, get_count).

init([]) ->
    {ok, 0}.

handle_call(increment, _From, State) ->
    NewState = State + 1,
    {reply, NewState, NewState};
handle_call(get_count, _From, State) ->
    {reply, State, State};
handle_call(_Request, _From, State) ->
    {reply, {error, bad_request}, State}.

handle_cast(_Msg, State) -> % Placeholder
    {noreply, State}.

terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.

Asynkrona anrop: `handle_cast`

Ibland behöver en klient inget svar utan vill bara skicka ett meddelande utan att vänta. Detta är ett asynkront anrop med gen_server:cast/2.

GenServer hanterar dessa meddelanden i sin callback handle_cast/2. Den tar två argument:

  • Message: Meddelandet från klienten.
  • State: GenServers aktuella interna tillstånd.

Den returnerar alltid {noreply, NewState}, eftersom inget svar skickas tillbaka till klienten.

Implementera `handle_cast` (återställning)

Vi lägger till en reset-funktion i vår räknare. Detta blir ett asynkront anrop, eftersom klienten inte behöver känna till det nya värdet direkt.

Kompilera och starta modulen som tidigare. Anropa `my_counter:increment().` några gånger och sedan `my_counter:reset().`. Du kommer att märka att `reset` returnerar direkt utan något värde.

-module(my_counter).
-behaviour(gen_server).
-export([start_link/0, increment/0, get_count/0, reset/0]).
-export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3]).

start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

increment() ->
    gen_server:call(?MODULE, increment).

get_count() ->
    gen_server:call(?MODULE, get_count).

reset() ->
    gen_server:cast(?MODULE, reset).

init([]) ->
    {ok, 0}.

handle_call(increment, _From, State) ->
    NewState = State + 1,
    {reply, NewState, NewState};
handle_call(get_count, _From, State) ->
    {reply, State, State};
handle_call(_Request, _From, State) ->
    {reply, {error, bad_request}, State}.

handle_cast(reset, _State) ->
    {noreply, 0};
handle_cast(_Msg, State) ->
    {noreply, State}.

terminate(_Reason, _State) -> ok.
code_change(_OldVsn, State, _Extra) -> {ok, State}.

Hantera GenServers tillstånd

GenServers styrka ligger i hur de hanterar tillstånd. Argumentet State skickas till varje callback, och callback-funktionen returnerar ett NewState.

  • Detta säkerställer att endast en process (själva GenServer-processen) någonsin ändrar dess tillstånd, vilket förhindrar kapplöpningstillstånd.
  • Det gör serverns interna logik enklare att förstå och resonera kring.
  • Tillståndet kan vara vilken Erlang-term som helst: ett heltal, en lista, en map, en post eller en komplex datastruktur.

Denna sekventiella meddelandehantering och explicita överföring av tillstånd är central i Erlangs samtidighetsmodell.

Typer av GenServer-anrop

Vilka av följande påståenden om GenServer-anrop är SANNA?

Sammanfattning: implementera GenServer

Du har nu byggt din första GenServer! Här är det vi gick igenom:

  • GenServers är standardbeteenden i OTP för att bygga servrar med tillstånd.
  • Callback-funktionen init/1 initierar serverns tillstånd.
  • gen_server:start_link skapar GenServer-processen.
  • handle_call/3 hanterar synkrona begäranden (klienten väntar på svar).
  • handle_cast/2 hanterar asynkrona meddelanden (klienten väntar inte).
  • GenServers hanterar sitt tillstånd genom att skicka det mellan callback-funktioner, vilket säkerställer sekventiella uppdateringar.

Härnäst ska vi se hur supervisors automatiskt kan starta om GenServers som har kraschat!

Gratis att börja

Lär dig Erlang med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
12
Lektioner
48

Vanliga frågor

Är lektionen ”Implementera GenServer-behavior” gratis?

Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Erlang OTP: Programmering av distribuerade och feltoleranta system, inklusive ”Implementera GenServer-behavior”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Erlang OTP: Programmering av distribuerade och feltoleranta system innehåller totalt 4 lektioner.

Vad lär jag mig i ”Implementera GenServer-behavior”?

Lär er implementera en GenServer, hantera tillstånd och behandla synkrona och asynkrona anrop – grunden för de flesta Erlang-komponenter. Ni övar på Erlang OTP: Programmering av distribuerade och feltoleranta system med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Erlang OTP: Programmering av distribuerade och feltoleranta system?

Du behöver inga förkunskaper. Utbildningen i Erlang OTP: Programmering av distribuerade och feltoleranta system på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Implementera GenServer-behavior”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Erlang OTP: Programmering av distribuerade och feltoleranta system-lektionen?

Ja. Varje Erlang OTP: Programmering av distribuerade och feltoleranta system-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Förstå OTP och behaviors
  2. Implementera GenServer-behavior
  3. Introduktion till supervisors
  4. Bygga OTP-applikationer och releaser
← Tillbaka till Erlang OTP: Programmering av distribuerade och feltoleranta system