[LINUX] Asynchrone E / A und nicht blockierende E / A.

Hintergrund

Ich schrieb über synchron / asynchron und blockierend / nicht blockierend und wollte sie persönlich zusammenfassen.

Funktionen der asynchronen E / A.

Das E / A-Modell, das benachrichtigt, wenn die E / A-Verarbeitung abgeschlossen ist, wird als asynchrone E / A bezeichnet. Die Benachrichtigung über den Abschluss der E / A an den Benutzer erfolgt per Signal oder Rückruf. Der Prozess kann bis zur Benachrichtigung mit einer anderen Verarbeitung fortgesetzt werden.

Es kann mit io_prep_pread (3), io_prep_pwrite (3), io_submit (2) implementiert werden. Es gibt auch Bibliotheksfunktionen wie aio_write und aio_read in der POSIX-Implementierung.

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);
}

Eine Zusammenfassung der verwendeten Funktionen. Der Inhalt von jedem ist wie folgt

io_queue_init (2) - Vorbereitung für asynchrone E / A. io_prep_pwrite(3) - io_submit (2) - Abonnieren Sie einen asynchronen E / A-Block in der ausstehenden Warteschlange io_getevents (2) - Lesen Sie asynchrone E / A-Ereignisse aus der Abschlusswarteschlange io_queue_release (3) - Geben Sie den benutzerbereichsbezogenen Kontext frei

Merkmale der nicht blockierenden E / A.

Bei nicht blockierenden E / A ist der Benutzer bereit, wenn der Dateideskriptor für E / A nicht bereit ist Sofortiger Fehler zurückgegeben (EAGAIN)

Sie kann implementiert werden, indem Sie das Flag O_NONBLOCK in open (2) angeben. Operationen an Dateideskriptoren, die mit O_NONBLOCK geöffnet wurden, lassen den Prozess nicht länger warten.

#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);
  }
}

Unterschied zwischen den beiden

Asynchrones Warten auf Benachrichtigungen im Hintergrund. Es ist nicht blockierend, den Status in festgelegten Intervallen zu überprüfen.

Die vollständige Nutzung dieser Funktionen und die Verwendung von E / A-Multiplexing führen zu einer ereignisgesteuerten Architektur.

C10K-Problem

Das "C10K-Problem" (10.000-Clients-Problem) ist ein Problem, bei dem der Server eine Panne aufweist, wenn die Anzahl der Clients zu groß wird, auch wenn keine Probleme hinsichtlich der Hardwareleistung auftreten. Es scheint zu passieren, wenn eine große Anzahl von Threads mit einer bestimmten Speichermenge erstellt wird.

Referenz: https://wa3.i-3-i.info/word11592.html

Über Spinlock

Eine kleine Entgleisung. Über den Begriff Spin Lock, der mehrmals auftaucht, wenn ich asynchron untersuche.

Wenn jede CPU in einer Multiprozessor-Umgebung gleichzeitig auf dieselbe Ressource (Ressource) zugreift Exklusiver Kontrollmechanismus verwendet. Bereiten Sie eine Sperrvariable im Speicher für eine Ressource vor. Und nur die CPU, die die Sperrvariable erhalten kann, kann auf die Ressource zugreifen.

Spin Lock ist eine einfache Möglichkeit, eine exklusive Steuerung in einem Multiprozessorsystem zu erreichen. Es wird oft verwendet. Die CPU im Besetztgewicht kann den Prozess jedoch nicht ausführen. Da es sich in einem Wartezustand befindet, wird die Verarbeitungseffizienz verbessert, wenn häufig ausgelastete Gewichte auftreten. Es wird schlimmer. In Anbetracht der Verarbeitungseffizienz sollten Ressourcen, die ausschließlich durch Spin Lock gesteuert werden, so oft wie möglich verwendet werden. Es ist notwendig, wie Unterteilung zu entwickeln.

Eine Art von Spin-Lock ist "Lese- / Schreib-Spin-Lock". Wenn bei dieser Drehsperre ein Konflikt bei der Leseverarbeitung von der CPU auftritt, wird die Sperre nicht ausgeführt. Sie können von beiden auf die Ressourcen zugreifen. Die ausschließliche Kontrolle wird wie gewohnt nur beim Schreiben durchgeführt. Lese- / Schreib-Spin-Sperren sind nützlich, wenn für Ressourcen viel Referenz verarbeitet wird.

Zusammenfassung

Referenzlink

Über asynchrone E / A [Den Unterschied zwischen nicht blockierenden E / A und asynchronen E / A verstehen](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

Asynchrone E / A und nicht blockierende E / A.
Ich habe versucht, das Verhalten von E / A-Eventlets in Python nicht zu blockieren
E / A-bezogene Zusammenfassung von Python und Fortan
Ich habe Java und Python verglichen!
Ich habe Klinge und Jinja2 verglichen
Ich berührte Tensorflow und Keras
Ich habe Qiskit und Blueqat (Anfänger) verglichen.
Ich habe Java und Ruby persönlich verglichen
Ich habe mit PyQt5 und Python3 gespielt
Ich habe versucht, asynchrone Verarbeitung mit Asyncio