[LINUX] E / S asynchrones et E / S non bloquantes

Contexte

J'ai écrit sur synchrone / asynchrone et bloquant / non bloquant, et je voulais personnellement les résumer.

Caractéristiques d'E / S asynchrones

Le modèle d'E / S qui avertit lorsque le traitement d'E / S est terminé est appelé E / S asynchrone. La notification d'achèvement d'E / S à l'utilisateur se fait par signal ou rappel. Le processus peut poursuivre d'autres traitements jusqu'à ce qu'il soit notifié.

Il peut être implémenté en utilisant io_prep_pread (3), io_prep_pwrite (3), io_submit (2). Il existe également des fonctions de bibliothèque telles que aio_write et aio_read dans l'implémentation dans POSIX.

struct {
    pthread_cond_t cond;
    pthread_mutex_t mtx;
    int flag;
} notified = {
    .cond   = PTHREAD_COND_INITIALIZER,
    .mtx    = PTHREAD_MUTEX_INITIALIZER,
    .flag   = 0
};

void thread_func(union sigval sv)
{
    printf("%s : aio_read from fd %d completed \n",
        __func__, sv.sival_int);

    pthread_mutex_lock(&notified.mtx);
    notified.flag = 1;
    pthread_cond_signal(& notified.cond);
    pthread_mutex_unlock(& notified.mtx);
}

main ()
{
    char a[BUFSIZ];
    struct aiocb aio = {
        .aio_offset   = 0,
        .aio_buf      = a,
        .aio_nbytes   = sizeof(a),
        .aio_reqprio  = 0,
        .aio_sigevent = {
            .sigev_notify            = SIGEV_THREAD,
            .sigev_notify_function   = thread_func,
            .sigev_notify_attributes = NULL
        }
    };

    aio.aio_fildes = open(argv[1], O_RDONLY);
    aio.aio_sigevent.sigev_value.sival_int = aio.aio_fildes;
    aio_read(&aio);

    /* do other jobs */

    pthread_mutex_lock(&notified.mtx);
    while (!notified.flag)
        pthread_cond_wait(&notified.cond, &notified.mtx);
    pthread_mutex_unlock(&notified.mtx);
}

Un résumé des fonctions utilisées. Le contenu de chacun est le suivant

io_queue_init (2) -Préparation des E / S asynchrones io_prep_pwrite(3) - io_submit (2) --Enregistre le bloc d'E / S asynchrone dans la file d'attente en attente io_getevents (2) -Lire les événements d'E / S asynchrones à partir de la file d'attente d'achèvement io_queue_release (3) - Libère le contexte lié à l'espace utilisateur

Caractéristiques des E / S non bloquantes

Dans les E / S non bloquantes, si le descripteur de fichier à E / S n'est pas prêt, à l'utilisateur Erreur immédiate renvoyée (EAGAIN)

Il peut être implémenté en spécifiant le drapeau O_NONBLOCK dans open (2). Les opérations sur les descripteurs de fichiers ouverts avec O_NONBLOCK ne font plus attendre le processus.

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

void set_fl(int fd, int flags);
void clr_fl(int fd, int flags);

char buf[100000];

int main(void) {
  int ntowrite, nwrite;
  char *ptr;

  ntowrite = read(STDIN_FILENO, buf, sizeof(buf));
  fprintf(stderr, "read %d byts\n", ntowrite);
  set_fl(STDOUT_FILENO, O_NONBLOCK);

  for (ptr = buf; ntowrite > 0; ) {
    errno = 0;
    nwrite = write(STDOUT_FILENO, ptr, ntowrite);
    fprintf(stderr, "nwrite = %d, errno = %d, err_message = '%s'\n", nwrite, errno, strerror(errno));
    if (nwrite > 0) {
      ptr += nwrite;
      ntowrite -= nwrite;
    }
  }

  clr_fl(STDOUT_FILENO, O_NONBLOCK);
  return 0;
}

void set_fl(int fd, int flags) {
  int val;

  if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
    fprintf(stderr, "fcntl F_GETFL error");
    exit(1);
  }

  val |= flags;  /* turn on flags */

  if (fcntl(fd, F_SETFL, val) < 0) {
    fprintf(stderr, "fcntl F_SETFL error");
    exit(1);
  }
}

void clr_fl(int fd, int flags) {
  int val;

  if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
    fprintf(stderr, "fcntl F_GETFL error");
    exit(1);
  }

  val &= ~flags;  /* turn flags off */

  if (fcntl(fd, F_SETFL, val) < 0) {
    fprintf(stderr, "fcntl F_SETFL error");
    exit(1);
  }
}

Différence entre les deux

Attente asynchrone des notifications en arrière-plan. Il n'est pas bloquant d'aller vérifier l'état à intervalles fixes.

En tirer pleinement parti et en utilisant le multiplexage d'E / S conduira à une architecture événementielle.

Problème C10K

Le "problème C10K" (problème de 10 000 clients) est un problème dans lequel le serveur se crevasse lorsque le nombre de clients devient trop important, même s'il n'y a pas de problème en termes de performances matérielles. Cela semble se produire lorsqu'un grand nombre de threads avec une certaine quantité de mémoire sont créés.

Référence: https://wa3.i-3-i.info/word11592.html

À propos de Spinlock

Un petit déraillement. À propos du terme verrouillage de rotation qui revient plusieurs fois lorsque j'enquête sur asynchrone.

Lorsque chaque CPU accède à la même ressource (ressource) en même temps dans un environnement multiprocesseur Mécanisme de contrôle exclusif utilisé. Préparez une variable de verrouillage en mémoire pour une ressource. Et seul le processeur qui peut obtenir la variable de verrouillage peut accéder à la ressource.

Le verrouillage rotatif est un moyen facile d'obtenir un contrôle exclusif dans un système multiprocesseur. Il est souvent utilisé. Cependant, la CPU pendant le poids occupé ne peut pas exécuter le processus. Puisqu'il sera dans un état d'attente, l'efficacité du traitement sera améliorée si les poids occupés se produisent fréquemment. Ça s'empire. Compte tenu de l'efficacité du traitement, les ressources qui sont exclusivement contrôlées par le verrouillage de rotation doivent être utilisées autant que possible. Il est nécessaire de concevoir comme subdiviser.

Un type de verrouillage de rotation est le "verrouillage de rotation en lecture / écriture". Dans ce verrou tournant, s'il y a un conflit dans le traitement de lecture depuis le CPU, le verrouillage n'est pas effectué. Vous pouvez accéder aux ressources des deux. Le contrôle exclusif est effectué comme d'habitude uniquement lors de l'écriture. Les verrous de rotation en lecture / écriture sont utiles lorsqu'il y a beaucoup de traitement de référence pour les ressources.

Résumé

Lien de référence

À propos des E / S asynchrones [Comprendre la différence entre les E / S non bloquantes et les E / S asynchrones](https://blog.takanabe.tokyo/2015/03/%E3%83%8E%E3%83%B3%E3%83%96% E3% 83% AD% E3% 83% 83% E3% 82% AD% E3% 83% B3% E3% 82% B0i / o% E3% 81% A8% E9% 9D% 9E% E5% 90% 8C% E6% 9C% 9Fi / o% E3% 81% AE% E9% 81% 95% E3% 81% 84% E3% 82% 92% E7% 90% 86% E8% A7% A3% E3% 81% 99% E3% 82% 8B /)

Recommended Posts

E / S asynchrones et E / S non bloquantes
J'ai essayé le comportement d'E / S Eventlet non bloquant en Python
Résumé relatif aux E / S de python et fortran
J'ai comparé Java et Python!
J'ai comparé lame et jinja2
J'ai touché Tensorflow et keras
J'ai comparé Qiskit et Blueqat (débutant)
J'ai personnellement comparé Java et Ruby
J'ai joué avec PyQt5 et Python3
J'ai essayé le traitement asynchrone en utilisant asyncio