web-dev-qa-db-fra.com

Quel est l'état des E / S asynchrones POSIX (AIO)?

Des pages disséminées sur le Web décrivent les installations POSIX AIO avec plus ou moins de détails. Aucun d'eux n'est terriblement récent. On ne sait pas exactement ce qu'ils décrivent. Par exemple, le "officiel" (?) site Web pour le support des E/S asynchrones du noyau Linux ici dit que les sockets ne fonctionnent pas, mais les pages de manuel "aio.h" sur mon Ubuntu 8.04. 1 poste de travail semble tous impliquer qu'il fonctionne pour des descripteurs de fichiers arbitraires. Ensuite, il y a n autre projet qui semble fonctionner au niveau de la bibliothèque avec encore moins de documentation.

J'aimerais savoir:

  • Quel est l'objectif de POSIX AIO? Étant donné que l'exemple le plus évident d'une implémentation que je peux trouver dit qu'il ne prend pas en charge les sockets, le tout me semble bizarre. Est-ce uniquement pour les E/S de disque asynchrones? Si oui, pourquoi l'API hyper-générale? Sinon, pourquoi les E/S disque sont-elles la première chose qui a été attaquée?
  • Où existe-t-il des exemples complets de programmes POSIX AIO que je peux consulter?
  • Quelqu'un l'utilise-t-il vraiment?
  • Quelles plateformes prennent en charge POSIX AIO? Quelles sont les parties qu'ils soutiennent? Quelqu'un supporte-t-il vraiment les "Toutes les E/S vers n'importe quel FD" qui <aio.h> semble promettre?

Les autres mécanismes de multiplexage à ma disposition sont parfaitement bons, mais les fragments aléatoires d'informations flottant là-bas m'ont rendu curieux.

93
Glyph

Les E/S réseau ne sont pas une priorité pour AIO car tous ceux qui écrivent des serveurs réseau POSIX utilisent une approche non bloquante basée sur les événements. L'ancienne approche Java "milliards de threads de blocage" est horrible.

Les E/S d'écriture sur disque sont déjà mises en mémoire tampon et les E/S de lecture sur disque peuvent être prélues dans le tampon à l'aide de fonctions telles que posix_fadvise. Cela laisse des E/S de disque directes et sans tampon comme seul objectif utile pour AIO.

Les E/S directes et sans tampon ne sont vraiment utiles que pour les bases de données transactionnelles, et celles-ci ont tendance à écrire leurs propres threads ou processus pour gérer leurs E/S disque.

Donc, à la fin, cela laisse POSIX AIO dans la position de ne pas servir tout but utile. Ne l'utilisez pas.

25
Zan Lynx

Faire des E/S de socket efficacement a été résolu avec kqueue, epoll, IO ports d'achèvement et autres. Faire des E/S de fichiers asynchrones est une sorte de retard (en dehors du chevauchement des fenêtres I/O et solaris support précoce pour posix AIO).

Si vous cherchez à faire des E/S de socket, vous feriez probablement mieux d'utiliser l'un des mécanismes ci-dessus.

L'objectif principal d'AIO est donc de résoudre le problème des E/S sur disque asynchrone. C'est probablement la raison pour laquelle Mac OS X ne prend en charge AIO que pour les fichiers normaux, et non pour les sockets (car kqueue le fait tellement mieux de toute façon).

Les opérations d'écriture sont généralement mises en cache par le noyau et vidées ultérieurement. Par exemple, lorsque la tête de lecture du lecteur passe par l'emplacement où le bloc doit être écrit.

Cependant, pour les opérations de lecture, si vous voulez que le noyau priorise et ordonne vos lectures, AIO est vraiment la seule option. Voici pourquoi le kernal peut (théoriquement) faire mieux que n'importe quelle application de niveau utilisateur:

  • Le noyau voit toutes les E/S de disque, pas seulement les tâches de disque de vos applications, et peut les commander au niveau global
  • Le noyau (peut) savoir où se trouve la tête de lecture du disque, et peut choisir les tâches de lecture que vous lui transmettez dans un ordre optimal, pour déplacer la tête sur la distance la plus courte
  • Le noyau peut tirer parti de file d'attente de commandes natives pour optimiser davantage vos opérations de lecture
  • Vous pouvez être en mesure d'émettre plus d'opérations de lecture par appel système à l'aide de lio_listio () qu'avec readv (), surtout si vos lectures ne sont pas (logiquement) contiguës, ce qui économise un tout petit peu la surcharge des appels système.
  • Votre programme peut être légèrement plus simple avec AIO car vous n'avez pas besoin d'un thread supplémentaire pour bloquer un appel en lecture ou en écriture.

Cela dit, posix AIO a une interface assez maladroite, par exemple:

  • Le seul moyen efficace et bien pris en charge de rappels d'événements est via les signaux, ce qui le rend difficile à utiliser dans une bibliothèque, car cela signifie utiliser les numéros de signal de l'espace de noms de signal global du processus. Si votre système d'exploitation ne prend pas en charge les signaux en temps réel, cela signifie également que vous devez parcourir toutes vos demandes en suspens pour déterminer laquelle a réellement été terminée (c'est le cas pour Mac OS X par exemple, pas Linux). La capture de signaux dans un environnement multithread crée également des restrictions délicates. Vous ne pouvez généralement pas réagir à l'événement à l'intérieur du gestionnaire de signal, mais vous devez élever un signal, écrire dans un canal ou utiliser signalfd () (sous linux).
  • lio_suspend () a les mêmes problèmes que select (), il ne s'adapte pas très bien avec le nombre de jobs.
  • lio_listio (), tel qu'implémenté, a un nombre assez limité de tâches que vous pouvez transmettre, et il n'est pas trivial de trouver cette limite de manière portable. Vous devez appeler sysconf (_SC_AIO_LISTIO_MAX), ce qui peut échouer, auquel cas vous pouvez utiliser la définition AIO_LISTIO_MAX, qui ne sont pas nécessairement définies, mais vous pouvez ensuite utiliser 2, qui est défini comme garanti pour être pris en charge.

En ce qui concerne les applications réelles utilisant posix AIO, vous pouvez jeter un œil à lighttpd (lighty), qui a également publié un mesure des performances lors de l'introduction du support.

La plupart des plates-formes posix prennent désormais en charge posix AIO (Linux, BSD, Solaris, AIX, tru64). Windows le prend en charge via ses E/S de fichiers qui se chevauchent. D'après ce que je comprends, seuls Solaris, Windows et Linux prennent réellement en charge l'async. déposer les E/S jusqu'au pilote, tandis que les autres systèmes d'exploitation émulent l'async. E/S avec threads du noyau. Linux étant l'exception, son implémentation AIO posix dans la glibc émule des opérations asynchrones avec des threads de niveau utilisateur, tandis que son interface native d'E/S asynchrone (io_submit () etc.) est vraiment asynchrone jusqu'au pilote, en supposant que le pilote le supporte .

Je pense qu'il est assez courant parmi les systèmes d'exploitation de ne pas prendre en charge le posix AIO pour aucun fd, mais de le limiter aux fichiers ordinaires.

69
Arvid

Un développeur libtorrent fournit un rapport à ce sujet: http://blog.libtorrent.org/2012/10/asynchronous-disk-io/

11
Allen

Il y a aio_write - implémenté dans la glibc; le premier appel de la fonction aio_read ou aio_write génère un certain nombre de threads en mode utilisateur, aio_write ou aio_read envoie des requêtes à ce thread, le thread procède à la lecture/écriture et à la fin, la réponse est envoyée au thread appelant bloqué.

Ther est également "réel" aio - pris en charge par le niveau du noyau (besoin de libaio pour cela, voir l'appel io_submit http://linux.die.net/man/2/io_submit ); nécessite également O_DIRECT pour cela (peut ne pas être pris en charge par tous les systèmes de fichiers, mais les principaux le prennent en charge)

vois ici:

http://lse.sourceforge.net/io/aio.html

http://linux.die.net/man/2/io_submit

Différence entre POSIX AIO et libaio sur Linux?

2
MichaelMoser