Qual è lo stato dell'I / O asincrono (AIO) POSIX?


93

Ci sono pagine sparse sul Web che descrivono le strutture POSIX AIO in quantità variabili di dettagli. Nessuno di loro è terribilmente recente. Non è chiaro cosa stiano descrivendo esattamente. Ad esempio, il sito web "ufficiale" (?) Per il supporto I / O asincrono del kernel Linux qui dice che i socket non funzionano, ma le pagine di manuale "aio.h" sulla mia stazione di lavoro Ubuntu 8.04.1 sembrano tutte implicare che funziona per descrittori di file arbitrari. Poi c'è un altro progetto che sembra funzionare a livello di libreria con ancora meno documentazione.

Mi piacerebbe sapere:

  • Qual è lo scopo di POSIX AIO? Dato che l'esempio più ovvio di un'implementazione che riesco a trovare dice che non supporta i socket, l'intera cosa mi sembra strana. È solo per l'I / O del disco asincrono? Se è così, perché l'API ipergenerale? In caso contrario, perché l'I / O del disco è la prima cosa che è stata attaccata?
  • Dove sono disponibili programmi AIO POSIX completi di esempio che posso guardare?
  • Qualcuno lo usa davvero, per davvero?
  • Quali piattaforme supportano POSIX AIO? Quali parti supportano? Qualcuno supporta davvero l'implicito "Any I / O to any FD" che <aio.h>sembra promettere?

Gli altri meccanismi di multiplexing a mia disposizione sono perfettamente buoni, ma i frammenti casuali di informazioni che fluttuano là fuori mi hanno incuriosito.

Risposte:


27

L'I / O di rete non è una priorità per AIO perché tutti coloro che scrivono server di rete POSIX utilizzano un approccio non bloccante basato sugli eventi. Il vecchio approccio Java "miliardi di thread bloccanti" fa schifo.

L'I / O di scrittura su disco è già bufferizzato e l'I / O di lettura su disco può essere precaricato nel buffer utilizzando funzioni come posix_fadvise. Ciò lascia l'I / O del disco diretto e senza buffer come unico scopo utile per AIO.

L'I / O diretto e senza buffer è veramente utile solo per i database transazionali e questi tendono a scrivere i propri thread o processi per gestire l'I / O del disco.

Quindi, alla fine, questo lascia POSIX AIO nella posizione di non servire a nessuno scopo utile. Non usarlo.


8
Che dire della lettura / scrittura da filesystem di rete (NFS, Samba)?
Alex B

1
bene. Ho diversi grandi autori stupidi che, se li lascio andare nella cache, colpiranno dirty_ratio ai picchi, bloccando tutti gli altri. Se uso solo l'IO diretto su di essi, è troppo lento. Se avessi solo 1 thread potrei gestire da solo, ma sarà difficile supportare diverse priorità IO in 1 battistrada. AIO + CFQ wouls sembrano davvero una buona combinazione, se AIO ha funzionato
n-alexander

37
Non sono d'accordo. L'I / O del disco tende ad essere bufferizzato ma può bloccarsi. Quando si esegue il poll () di un file FD, segnala sempre che l'FD è leggibile, anche quando si bloccherà. Ciò rende impossibile eseguire operazioni non bloccanti sui file del disco in modo evento, a meno che non si utilizzino thread o AIO.
Hongli

2
@ Matt: l'ordine non è importante per i socket del datagramma. @Zan: I / O asincrono è molto utile per il pre-buffer dei dati di streaming in tempo reale, ad esempio i lettori multimediali.
Ben Voigt

13
Non è vero che l'AIO è inutile nei sistemi basati su eventi. Puoi effettivamente arrivare a una rete a copia zero con AIO appropriato, cosa che non puoi con la notifica basata su eventi a recv (). Altre cose potrebbero cospirare per rendere questo perlopiù una limitazione teorica, ma penso che la mancanza di un AIO adeguato (alla OVERLAPPED su Windows) sia uno degli ultimi grandi buchi in Linux.
Jon Watte

69

Fare I / O socket in modo efficiente è stato risolto con kqueue, epoll, porte di completamento IO e simili. Fare I / O su file asincrono è una specie di arrivo in ritardo (a parte l'I / O sovrapposto di Windows e il supporto anticipato di Solaris per posix AIO).

Se stai cercando di fare I / O socket, probabilmente stai meglio usando uno dei meccanismi di cui sopra.

Lo scopo principale di AIO è quindi quello di risolvere il problema dell'I / O asincrono del disco. Questo è molto probabilmente il motivo per cui Mac OS X supporta AIO solo per i file normali e non per i socket (poiché kqueue lo fa molto meglio comunque).

Le operazioni di scrittura vengono in genere memorizzate nella cache dal kernel e cancellate in un secondo momento. Ad esempio, quando la testina di lettura dell'unità passa dalla posizione in cui deve essere scritto il blocco.

Tuttavia, per le operazioni di lettura, se vuoi che il kernel dia la priorità e ordini le tue letture, AIO è davvero l'unica opzione. Ecco perché il kernal può (teoricamente) farlo meglio di qualsiasi applicazione a livello utente:

  • Il kernel vede tutto l'I / O del disco, non solo i lavori del disco delle applicazioni, e può ordinarli a livello globale
  • Il kernel (può) sapere dove si trova la testina di lettura del disco e può scegliere i lavori di lettura che gli vengono trasmessi in ordine ottimale, per spostare la testina la distanza più breve
  • Il kernel può trarre vantaggio dall'accodamento nativo dei comandi per ottimizzare ulteriormente le operazioni di lettura
  • Potresti essere in grado di eseguire più operazioni di lettura per chiamata di sistema usando lio_listio () che con readv (), specialmente se le tue letture non sono (logicamente) contigue, risparmiando un po 'di overhead delle chiamate di sistema.
  • Il tuo programma potrebbe essere leggermente più semplice con AIO poiché non hai bisogno di un thread aggiuntivo per bloccare in una chiamata di lettura o scrittura.

Detto questo, posix AIO ha un'interfaccia piuttosto scomoda, ad esempio:

  • L'unico mezzo efficiente e ben supportato di callback di eventi è tramite segnali, il che lo rende difficile da usare in una libreria, poiché significa usare numeri di segnale dallo spazio dei nomi del segnale globale del processo. Se il tuo sistema operativo non supporta i segnali in tempo reale, significa anche che devi scorrere tutte le tue richieste in sospeso per capire quale è effettivamente terminata (questo è il caso di Mac OS X, ad esempio, non Linux). La cattura dei segnali in un ambiente multi-threading comporta anche alcune restrizioni complicate. Normalmente non puoi reagire all'evento all'interno del gestore del segnale, ma devi alzare un segnale, scrivere su una pipe o usare signalfd () (su linux).
  • lio_suspend () ha gli stessi problemi di select (), non si adatta molto bene con il numero di lavori.
  • lio_listio (), come implementato ha un numero abbastanza limitato di lavori che puoi passare, e non è banale trovare questo limite in modo portabile. Devi chiamare sysconf (_SC_AIO_LISTIO_MAX), che potrebbe fallire, nel qual caso puoi usare la definizione AIO_LISTIO_MAX, che non sono necessariamente definiti, ma poi puoi usare 2, che è definito come garantito per essere supportato.

Per quanto riguarda l'applicazione del mondo reale che utilizza posix AIO, potresti dare un'occhiata a lighttpd (lighty), che ha anche pubblicato una misurazione delle prestazioni quando si introduce il supporto.

La maggior parte delle piattaforme posix supporta posix AIO ormai (Linux, BSD, Solaris, AIX, tru64). Windows lo supporta tramite il suo file I / O sovrapposto. La mia comprensione è che solo Solaris, Windows e Linux supportano veramente l'asincronia. I / O dei file fino al driver, mentre gli altri sistemi operativi emulano il file async. I / O con thread del kernel. Linux è l'eccezione, la sua implementazione AIO posix in glibc emula operazioni asincrone con thread a livello utente, mentre la sua interfaccia I / O asincrona nativa (io_submit () ecc.) È veramente asincrona fino al driver, assumendo che il driver lo supporti .

Credo che sia abbastanza comune tra i sistemi operativi non supportare posix AIO per qualsiasi fd, ma limitarlo ai file normali.


Windows ha avuto OVERLAPPED I / O che supporta i file su disco da quando è uscito Win32. Non è affatto nuovo. E su POSIX, lo spazio dei nomi del segnale non è globale per il processo, è per thread. I segnali vengono inviati a thread particolari (o aio è un'eccezione, non puoi ricordarlo per certo?).
Ben Voigt

1
Non c'è modo di specificare a quale thread AIO invia i suoi segnali. Su Linux sembra che lo distribuisca principalmente al thread che ha emesso il comando aio _ * (), ma non sempre (l'unica soluzione che ho trovato è stata creare più signalfds). Qualche anno fa c'era una patch per Linux sulla mailing list del kernel che l'avrebbe aggiunta, ma non è mai arrivata e sarebbe stata un'estensione di POSIX. Su Mac OS X, i segnali sembrano essere principalmente inviati al thread principale (nella mia esperienza). Non penso che POSIX richieda un comportamento specifico, se lo fa, mi piacerebbe vedere la parte delle specifiche.
Arvid

5
L'implementazione di aio_read / write da parte di glibc utilizza i thread in userland, quindi qui non vengono utilizzati nemmeno i thread del kernel.
Marenz

Cosa significa "sempre tipicamente"? Le scritture vengono memorizzate nella cache dal kernel per qualsiasi metodo o quando si utilizza AIO? Sembra che ci debba essere un modo per far sì che il software sia certo che la scrittura sia stata completata con successo; altrimenti, l'integrità e gli obiettivi transazionali non possono essere raggiunti.
MikeB

Un altro esempio dal vivo in cui puoi usare AIO è nginx. Sono supportate tutte le modalità. Se preferisci l'offload ai thread userland, normalmente lo troverai molto peggio dell'IO diretto, ma l'AIO nativo di Linux è alla pari con l'IO diretto. La situazione in cui AIO può essere sostanzialmente vantaggioso è la forte pressione della cache della pagina. La differenza concettuale tra Async e Direct IOs può essere vista qui ftp.dei.uc.pt/pub/linux/kernel/people/suparna/aio-linux.pdf
wick


2

C'è aio_write - implementato in glibc; la prima chiamata della funzione aio_read o aio_write genera un numero di thread in modalità utente, richieste di post aio_write o aio_read a quel thread, il thread esegue la pread / pwrite e quando ha finito la risposta viene inviata nuovamente al thread chiamante bloccato.

C'è anche un aio 'reale' - supportato dal livello del kernel (serve libaio per questo, vedi la chiamata io_submit http://linux.die.net/man/2/io_submit ); serve anche O_DIRECT per quello (inoltre potrebbe non essere supportato da tutti i file system, ma i principali lo supportano)

Vedere qui:

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

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

Differenza tra POSIX AIO e libaio su Linux?


Molte delle carenze di aio_writesono coperte sopra, in stackoverflow.com/a/5307557/13564
Glyph
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.