Recherche…


Introduction

Dans cet article, nous allons discuter de la manière dont le concept Eventloop a émergé et de la manière dont il peut être utilisé pour les serveurs hautes performances et les applications pilotées par des événements telles que les interfaces graphiques.

Comment le concept de boucle d'événement a évolué.

Eventloop en pseudo-code

Une boucle d'événement est une boucle qui attend des événements et réagit à ces événements

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

Exemple de serveur HTTP mono-thread sans boucle d'événement

    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)

Voici une forme simple d'un serveur HTTP qui est un thread unique mais pas de boucle d'événement. Le problème ici est qu'il attend que chaque requête soit terminée avant de commencer à traiter la suivante. S'il faut un certain temps pour lire les en-têtes de requête HTTP ou pour extraire le fichier du disque, nous devrions pouvoir commencer à traiter la requête suivante en attendant que cela se termine.

La solution la plus courante consiste à rendre le programme multithread.

Exemple de serveur HTTP multithread sans boucle d'événement

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)

Maintenant, nous avons rendu notre petit serveur HTTP multi-thread. De cette façon, nous pouvons immédiatement passer à la requête suivante car la requête en cours est exécutée dans un thread d'arrière-plan. De nombreux serveurs, y compris Apache, utilisent cette approche.

Mais ce n'est pas parfait. Une limitation est que vous ne pouvez générer que beaucoup de threads. Pour les charges de travail où vous avez un grand nombre de connexions, mais chaque connexion ne nécessite qu'une attention de temps en temps, le modèle multi-thread ne fonctionnera pas très bien. La solution pour ces cas est d'utiliser une boucle d'événement:

Exemple de serveur HTTP avec boucle d'événements

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)

Espérons que ce pseudo-code soit intelligible. Voici ce qui se passe: nous attendons que les choses se passent. Chaque fois qu'une nouvelle connexion est créée ou qu'une connexion existante nécessite notre attention, nous nous en occupons, puis revenons à l'attente. De cette façon, nous fonctionnons bien quand il y a beaucoup de connexions et que chacune d'elles nécessite rarement une attention.

Dans une application réelle (pas de pseudocode) fonctionnant sous Linux, la partie "Attendre l'événement suivant" serait implémentée en appelant l'appel système poll () ou epoll (). Les parties "commencer à lire / écrire quelque chose dans un socket" seraient implémentées en appelant les appels système recv () ou send () en mode non bloquant.

Référence:

[1]. "Comment fonctionne une boucle d'événement?" [En ligne]. Disponible: https://www.quora.com/How-does-an-event-loop-work



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow