Effectuer efficacement les E / S de socket a été résolu avec kqueue, epoll, les ports d'achèvement d'E / S et autres. Faire des E / S de fichiers asynchrones est une sorte de retard (à part les E / S superposées de Windows et le support précoce de Solaris pour posix AIO).
Si vous recherchez 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 de disque asynchrones. C'est très probablement pourquoi Mac OS X ne prend en charge AIO que pour les fichiers normaux, et non les sockets (puisque 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 supprimé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 noyau peut (théoriquement) faire cela mieux que n'importe quelle application de niveau utilisateur:
- Le noyau voit toutes les E / S disque, pas seulement les tâches de disque de vos applications, et peut les ordonner au niveau global
- Le noyau sait (peut) 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 la mise en file d'attente des commandes native en d' pour optimiser davantage vos opérations de lecture
- Vous pourrez peut-être effectuer plus d'opérations de lecture par appel système en utilisant lio_listio () qu'avec readv (), surtout si vos lectures ne sont pas (logiquement) contiguës, économisant un tout petit peu de surcharge d'appel 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 des rappels d'événements est via des signaux, ce qui le rend difficile à utiliser dans une bibliothèque, car cela signifie utiliser des numéros de signaux de l'espace de noms de signaux 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 requêtes en suspens pour déterminer laquelle est réellement terminée (c'est le cas pour Mac OS X par exemple, pas pour Linux). La capture de signaux dans un environnement multi-thread entraîne également des restrictions délicates. Vous ne pouvez généralement pas réagir à l'événement à l'intérieur du gestionnaire de signaux, mais vous devez augmenter un signal, écrire dans un tube ou utiliser signalfd () (sous Linux).
- lio_suspend () a les mêmes problèmes que select (), il ne s'adapte pas très bien au nombre de jobs.
- lio_listio (), tel qu'implémenté, a un nombre assez limité de tâches que vous pouvez transmettre, et ce n'est pas anodin 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 n'est pas nécessairement définie, mais vous pouvez alors utiliser 2, qui est défini comme étant garanti d'ê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é une 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 superposées. Je crois comprendre que seuls Solaris, Windows et Linux prennent vraiment en charge l'async. E / S de fichier jusqu'au pilote, tandis que les autres systèmes d'exploitation émulent l'async. E / S avec les threads du noyau. Linux étant l'exception, son implémentation AIO posix dans la glibc émule les opérations asynchrones avec des threads de niveau utilisateur, alors que son interface d'E / S asynchrone native (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 posix AIO pour aucun fd, mais de le limiter aux fichiers normaux.