¿Cuál es el estado de la E / S asíncrona (AIO) POSIX?

93

Hay páginas esparcidas por la web que describen las instalaciones POSIX AIO con distintos detalles. Ninguno de ellos es terriblemente reciente. No está claro qué es exactamente lo que están describiendo. Por ejemplo, el sitio web "oficial" (?) Para el soporte de E / S asíncronas del kernel de Linux aquí dice que los sockets no funcionan, pero las páginas del manual "aio.h" en mi estación de trabajo Ubuntu 8.04.1 parecen implicar que funciona para descriptores de archivos arbitrarios. Luego hay otro proyecto que parece funcionar en la capa de la biblioteca con incluso menos documentación.

Me gustaría saber:

  • ¿Cuál es el propósito de POSIX AIO? Dado que el ejemplo más obvio de una implementación que puedo encontrar dice que no admite sockets, todo me parece extraño. ¿Es solo para E / S de disco asíncrono? Si es así, ¿por qué la API hipergeneral? Si no es así, ¿por qué la E / S de disco es lo primero que fue atacado?
  • ¿Dónde hay ejemplos de programas POSIX AIO completos que pueda ver?
  • ¿Alguien realmente lo usa, de verdad?
  • ¿Qué plataformas son compatibles con POSIX AIO? ¿Qué partes apoyan? ¿Alguien realmente apoya el implícito "Cualquier E / S a cualquier FD" que <aio.h>parece prometer?

Los otros mecanismos de multiplexación disponibles para mí son perfectamente buenos, pero los fragmentos aleatorios de información que flotan por ahí me han dado curiosidad.

Glifo
fuente

Respuestas:

27

La E / S de red no es una prioridad para AIO porque todos los que escriben servidores de red POSIX utilizan un enfoque sin bloqueo basado en eventos. El enfoque antiguo de Java de "miles de millones de hilos de bloqueo" apesta horriblemente.

La E / S de escritura de disco ya está almacenada en búfer y la E / S de lectura de disco se puede recuperar previamente en el búfer mediante funciones como posix_fadvise. Eso deja la E / S de disco directa y sin búfer como el único propósito útil para AIO.

La E / S directa sin búfer solo es realmente útil para las bases de datos transaccionales, y estas tienden a escribir sus propios hilos o procesos para administrar la E / S de su disco.

Entonces, al final eso deja a POSIX AIO en la posición de no cumplir ningún propósito útil. No lo use.

Zan Lynx
fuente
8
¿Qué pasa con la lectura / escritura desde sistemas de archivos de red (NFS, Samba)?
Alex B
1
bien. Tengo varios escritores grandes y tontos que, si los dejo ir al caché, golpearán dirty_ratio en los picos, bloqueando a todos los demás. Si solo uso IO directo en ellos, es demasiado lento. Si solo tuviera 1 hilo, podría manejarlo por mi cuenta, pero sería difícil admitir diferentes prioridades IO en 1 paso. AIO + CFQ realmente parecería una buena combinación, si AIO funcionara
n-alexander
37
Estoy en desacuerdo. La E / S de disco tiende a almacenarse en búfer, pero puede bloquearse. Al sondear () un archivo FD, siempre informa que el FD es legible, incluso cuando se bloqueará. Esto hace que sea imposible realizar operaciones sin bloqueo en archivos de disco de manera uniforme, a menos que se utilicen subprocesos o AIO.
Hongli
2
@Matt: El orden no es importante para los sockets de datagramas. @Zan: Async I / O es muy bueno para almacenar previamente en el búfer datos de transmisión en tiempo real, por ejemplo, reproductores multimedia.
Ben Voigt
13
No es cierto que AIO sea inútil en sistemas basados ​​en eventos. En realidad, puede acceder a la red de copia cero con el AIO adecuado, lo que no puede con la notificación basada en eventos a recv (). Otras cosas pueden conspirar para hacer de esto principalmente una limitación teórica, pero creo que la falta de AIO adecuada (a la OVERLAPPED en Windows) es uno de los últimos grandes agujeros en Linux.
Jon Watte
70

Hacer E / S de socket de manera eficiente se ha resuelto con kqueue, epoll, puertos de finalización de E / S y similares. Hacer E / S de archivos asincrónicas es una especie de llegada tardía (aparte de las E / S superpuestas de Windows y el soporte temprano de Solaris para posix AIO).

Si está buscando hacer E / S de socket, probablemente sea mejor que use uno de los mecanismos anteriores.

El objetivo principal de AIO es, por tanto, resolver el problema de la E / S de disco asíncrona. Es muy probable que esta sea la razón por la que Mac OS X solo admite AIO para archivos normales y no sockets (ya que kqueue lo hace mucho mejor de todos modos).

Las operaciones de escritura generalmente se almacenan en caché por el kernel y se eliminan en un momento posterior. Por ejemplo, cuando el cabezal de lectura de la unidad pasa por la ubicación donde se va a escribir el bloque.

Sin embargo, para las operaciones de lectura, si desea que el kernel priorice y ordene sus lecturas, AIO es realmente la única opción. He aquí por qué el kernal puede (teóricamente) hacerlo mejor que cualquier aplicación de nivel de usuario:

  • El kernel ve todas las E / S del disco, no solo los trabajos de disco de las aplicaciones, y puede ordenarlos a nivel global
  • El kernel (puede) saber dónde está el cabezal de lectura del disco y puede elegir los trabajos de lectura que le transmita en el orden óptimo, para mover el cabezal la distancia más corta
  • El kernel puede aprovechar la cola de comandos nativa para optimizar aún más sus operaciones de lectura
  • Es posible que pueda realizar más operaciones de lectura por llamada al sistema usando lio_listio () que con readv (), especialmente si sus lecturas no son (lógicamente) contiguas, lo que ahorra una pequeña parte de la sobrecarga de llamadas del sistema.
  • Su programa puede ser un poco más simple con AIO ya que no necesita un hilo adicional para bloquear en una llamada de lectura o escritura.

Dicho esto, posix AIO tiene una interfaz bastante incómoda, por ejemplo:

  • El único medio eficiente y bien soportado de devoluciones de llamada de eventos es a través de señales, lo que dificulta su uso en una biblioteca, ya que significa usar números de señal del espacio de nombres de señal global del proceso. Si su sistema operativo no admite señales en tiempo real, también significa que debe recorrer todas sus solicitudes pendientes para averiguar cuál terminó realmente (este es el caso de Mac OS X, por ejemplo, no de Linux). La captura de señales en un entorno de subprocesos múltiples también crea algunas restricciones complicadas. Por lo general, no puede reaccionar al evento dentro del controlador de señales, pero debe generar una señal, escribir en una tubería o usar signalfd () (en Linux).
  • lio_suspend () tiene los mismos problemas que select (), no escala muy bien con la cantidad de trabajos.
  • lio_listio (), tal como se implementó, tiene un número bastante limitado de trabajos que puede pasar, y no es trivial encontrar este límite de manera portátil. Debe llamar a sysconf (_SC_AIO_LISTIO_MAX), que puede fallar, en cuyo caso puede usar la definición AIO_LISTIO_MAX, que no está necesariamente definida, pero luego puede usar 2, que se define como compatible con garantía.

En cuanto a la aplicación del mundo real que usa posix AIO, puede echar un vistazo a lighttpd (lighty), que también publicó una medición de rendimiento al presentar el soporte.

La mayoría de las plataformas posix soportan posix AIO por ahora (Linux, BSD, Solaris, AIX, tru64). Windows lo admite a través de su E / S de archivos superpuestos. Tengo entendido que solo Solaris, Windows y Linux realmente admiten async. E / S de archivos hasta el controlador, mientras que los otros sistemas operativos emulan el archivo async. E / S con subprocesos del kernel. Linux es la excepción, su implementación posix AIO en glibc emula operaciones asíncronas con subprocesos de nivel de usuario, mientras que su interfaz nativa de E / S asíncrona (io_submit (), etc.) es verdaderamente asíncrona hasta el controlador, asumiendo que el controlador lo admite. .

Creo que es bastante común entre los sistemas operativos no admitir posix AIO para ningún fd, pero restringirlo a archivos normales.

Arvid
fuente
Windows ha tenido archivos de disco de soporte de E / S SUPERPUESTOS desde que apareció Win32. No es nada nuevo. Y en POSIX, el espacio de nombres de la señal no es global de proceso, es por subproceso. Las señales se envían a subprocesos particulares (o es aio una excepción a eso, ¿no puede recordar con certeza?).
Ben Voigt
1
No hay forma de especificar a qué subproceso AIO envía sus señales. En Linux, parece entregarlo principalmente al hilo que emitió el comando aio _ * (), pero no siempre (la única solución que encontré para esto fue crear múltiples signalfds). Hubo un parche de Linux en la lista de correo del kernel hace unos años que agregaría esto, pero nunca llegó, y habría sido una extensión de POSIX. En Mac OS X, las señales parecen enviarse principalmente al hilo principal (en mi experiencia). No creo que POSIX requiera un comportamiento específico, si lo hace, me encantaría ver la parte de la especificación.
Arvid
5
La implementación de glibc de aio_read / write usa subprocesos en el área de usuario, por lo que aquí ni siquiera se usan subprocesos del kernel.
Marenz
¿Qué significa "siempre típicamente"? Las escrituras se almacenan en caché por el kernel para cualquier método, o cuando se usa AIO? Parece que debe haber una forma de que el software se asegure de que la escritura se haya completado correctamente; de lo contrario, no se pueden cumplir los objetivos transaccionales y de integridad.
MikeB
Otro ejemplo en vivo en el que puede usar AIO es nginx. Todos los modos son compatibles. Si prefiere descargar a subprocesos de usuario, normalmente lo encontrará mucho peor que el IO directo, pero el AIO nativo de Linux está a la par con el IO directo. La situación en la que AIO puede ser sustancialmente beneficiosa es la presión severa de la caché de página. Diferencia conceptual entre asíncrono y Direct OI puede ser visto aquí ftp.dei.uc.pt/pub/linux/kernel/people/suparna/aio-linux.pdf
mecha
2

Hay aio_write - implementado en glibc; La primera llamada de la función aio_read o aio_write genera una cantidad de subprocesos en modo de usuario, solicitudes de publicación de aio_write o aio_read a ese subproceso, el subproceso hace pread / pwrite y cuando termina, la respuesta se vuelve a publicar en el subproceso de llamada bloqueado.

También es aio 'real', compatible con el nivel del kernel (necesita libaio para eso, consulte la llamada io_submit http://linux.die.net/man/2/io_submit ); también necesita O_DIRECT para eso (también puede que no sea compatible con todos los sistemas de archivos, pero los principales sí lo admiten)

mira aquí:

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

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

¿Diferencia entre POSIX AIO y libaio en Linux?

MichaelMoser
fuente
Muchas de las deficiencias de aio_write se cubren anteriormente, en stackoverflow.com/a/5307557/13564
Glyph