Zoeken…


Invoering

In dit bericht gaan we bespreken hoe het concept van Eventloop is ontstaan en hoe het kan worden gebruikt voor krachtige servers en evenementgestuurde toepassingen zoals GUI's.

Hoe het concept van event loop evolueerde.

Eventloop in pseudo-code

Een gebeurtenislus is een lus die op gebeurtenissen wacht en vervolgens op die gebeurtenissen reageert

while true:
    wait for something to happen
    react to whatever happened

Voorbeeld van een HTTP-server met één thread zonder gebeurtenislus

    while true:
    socket = wait for the next TCP connection
    read the HTTP request headers from (socket)
    file_contents = fetch the requested file from disk
    write the HTTP response headers to (socket)
    write the (file_contents) to (socket)
    close(socket)

Hier is een eenvoudige vorm van een HTTP-server die uit één thread bestaat, maar geen event-lus. Het probleem hier is dat het wacht totdat elk verzoek is voltooid voordat het begint met het verwerken van het volgende. Als het een tijdje duurt om de HTTP-verzoekkopteksten te lezen of om het bestand van de schijf op te halen, moeten we in staat zijn om het volgende verzoek te verwerken terwijl we wachten tot het klaar is.

De meest gebruikelijke oplossing is om het programma multi-threaded te maken.

Voorbeeld van een multi-threaded HTTP-server zonder gebeurtenislus

function handle_connection(socket):
    read the HTTP request headers from (socket)
    file_contents = fetch the requested file from disk
    write the HTTP response headers to (socket)
    write the (file_contents) to (socket)
    close(socket)
while true:
    socket = wait for the next TCP connection
    spawn a new thread doing handle_connection(socket)

Nu hebben we onze kleine HTTP-server multi-threaded gemaakt. Op deze manier kunnen we meteen doorgaan naar het volgende verzoek omdat het huidige verzoek in een achtergrondthread wordt uitgevoerd. Veel servers, waaronder Apache, gebruiken deze aanpak.

Maar het is niet perfect. Een beperking is dat je slechts zoveel threads kunt spawnen. Voor werkbelastingen waar u een groot aantal verbindingen hebt, maar elke verbinding slechts af en toe aandacht behoeft, zal het multi-threaded model niet zo goed presteren. De oplossing voor die gevallen is het gebruik van een gebeurtenislus:

Voorbeeld van een HTTP-server met gebeurtenislus

while true:
    event = wait for the next event to happen
    if (event.type == NEW_TCP_CONNECTION):
        conn = new Connection
        conn.socket = event.socket
        start reading HTTP request headers from (conn.socket) with userdata = (conn)
    else if (event.type == FINISHED_READING_FROM_SOCKET):
        conn = event.userdata
        start fetching the requested file from disk with userdata = (conn)
    else if (event.type == FINISHED_READING_FROM_DISK):
        conn = event.userdata
        conn.file_contents = the data we fetched from disk
        conn.current_state = "writing headers"
        start writing the HTTP response headers to (conn.socket) with userdata = (conn)
    else if (event.type == FINISHED_WRITING_TO_SOCKET):
        conn = event.userdata
        if (conn.current_state == "writing headers"):
            conn.current_state = "writing file contents"
            start writing (conn.file_contents) to (conn.socket) with userdata = (conn)
        else if (conn.current_state == "writing file contents"):
            close(conn.socket)

Hopelijk is deze pseudocode begrijpelijk. Dit is wat er aan de hand is: we wachten tot er dingen gebeuren. Wanneer een nieuwe verbinding tot stand wordt gebracht of een bestaande verbinding onze aandacht nodig heeft, gaan we ermee om en gaan we terug naar wachten. Op die manier presteren we goed als er veel connecties zijn en elk slechts zelden aandacht behoeft.

In een echte toepassing (niet pseudocode) die op Linux draait, zou het gedeelte "wachten op de volgende gebeurtenis" worden geïmplementeerd door de systeemaanroep poll () of epoll () aan te roepen. De "begin met lezen / schrijven van iets naar een socket" -onderdelen zou worden geïmplementeerd door de systeemaanroepen recv () of send () aan te roepen in een niet-blokkerende modus.

Referentie:

[1]. "Hoe werkt een gebeurtenislus?" [Online]. Beschikbaar: https://www.quora.com/How-does-an-event-loop-work



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow