Cosa limita l'I / O file asincrono multipiattaforma?

4

Guardando una gamma di linguaggi multipiattaforma, librerie e toolkit della GUI, noto spesso un'assenza evidente di supporto per l'I / O di file asincrono. Questo sembra un fattore troppo comune per essere una supervisione casuale in tutti loro. Tuttavia non ne so abbastanza dei sistemi operativi individuali o di questi linguaggi / librerie per capire perché non lo presentano.

Ecco alcuni esempi.

  • Il asyncio di Python (iniziato in 3.4) contiene metodi per gestire in modo asincrono l'attività di rete e di sottoprocesso, ma nulla per leggere i file dal disco.
  • La libreria Twisted per la programmazione basata su eventi e protocolli in Python sembra non contenere nulla per async file I / O.
  • Il qt 5 QFile in particolare non emette il readyRead o bytesWritten segnali, in contrasto con altre implementazioni QIODevice per il networking.
  • Tutte le classi correlate ai file di wxWidget sono completamente sincrone.

Questi sono solo gli ultimi quattro che ho cercato; è possibile che ho scelto quattro di fila senza file asincrono IO per coincidenza, ma sono tutti molto popolari e stabili. So che non sono le uniche librerie popolari che ho usato negli ultimi dieci anni in cui mi sono perso.

Forse c'è meno richiesta di questo rispetto alla lettura dei dati da un socket o sottoprocesso, ma è così poco da essere considerato indesiderato? Un file apparentemente locale potrebbe essere sull'altro lato di una connessione di rete (ad esempio una condivisione SMB o una montatura NSF) che non è affatto vero che l'accesso al disco locale sarà più veloce di quanto un utente noterebbe . Non è nemmeno necessariamente vero per un SSD locale, nuovo di zecca per quella materia.

Consigli comuni per eseguire il proprio file asincrono IO con thread sembra contrario alla saggezza prevalente, quando così tanto di ciò che motiva l'uso del toolkit è non a far da te, specialmente quando si tratta di qualcosa che coinvolge il threading. So che è possibile, e forse non così difficile, ma non ci sono molte altre cose che sono comunemente disponibili in queste librerie e lingue.

Prendiamo Qt come esempio (estraendolo da un commento su una risposta). In Qt, se voglio fare X senza mettere in pausa il mio intero programma, posso usare Y :

  • Se X = ridisegna una tela; Y = usa segnali e slot
  • Se X = legge i dati via HTTP; Y = usa segnali e slot
  • Se X = recupera i dati da un sottoprocesso; Y = usa segnali e slot
  • Ma se X = recupera i dati dal disco rigido; Y = implementa qualcosa con un thread, o forse due thread, due semafori, speciali indicatori di memoria condivisa e forse un mucchio di altre cose.

Se sia o non sia semplice per me implementare è fuori questione. Il punto è che il file IO è un'operazione che può bloccare, ma è costantemente dispari in toolkit e librerie cross-platform non avendo una gestione di alto livello.

Fondamentalmente sembra che questa omissione richieda una maggiore complessità da parte dell'utente della biblioteca per un'attività non insolita, quando l'obiettivo di queste librerie è quello di assorbire quel tipo di complessità di implementazione di basso livello. Sembra strano che l'inserimento di un file locale sull'altro lato di un server web locale lo renda più semplice per accedere a un programma basato su eventi.

Per essere chiari, e per chiarire la mia domanda, questo non è un reclamo relativo alla mancanza di funzionalità. Voglio capire meglio le librerie multipiattaforma e le differenze del sistema operativo, quindi sono sinceramente curioso di sapere perché questa situazione è sorto e se c'è una qualche limitazione tecnica o altro vincolo alla radice di esso.

    
posta detly 24.01.2018 - 06:04
fonte

2 risposte

4

Vedo due problemi relativi all'IO file asincrono:

  • Assenza di file asincrono IO su Linux.
  • IO asincrone basato su completamento e prontezza

Linux fornisce syscalls io_setup , io_submit , io_getevents e pochi altri per gestire file IO asincroni. Ha i seguenti vincoli:

  • Il file deve essere aperto con O_DIRECT flag, ad es. tutte le operazioni ignorano la cache dei file. Questo da solo lo rende inutile per la maggior parte delle applicazioni.
  • Sia l'offset del file che l' indirizzo del buffer dovrebbero essere allineati di 512 o 4096 byte (a seconda del filesystem sottostante). Questo è fatto per rendere possibile la lettura / scrittura dei dati direttamente da / verso il buffer utente.

Se l'utente viola uno di questi vincoli, io_submit eseguirà silenziosamente tutte le operazioni in modo sincrono.

Ho letto da qualche parte sulla mailing list Nginx anni fa che questa API è stata implementata da Oracle per il loro database. Avevano solo bisogno di un file I / O asincrono che ignorasse la cache dei file (qualcosa che fanno i database), quindi hanno lasciato incompleta l'implementazione.

POSIX fornisce aio_write , aio_read funzioni, ma su Linux queste sono implementate nello userspace usando il pool di thread che rende le implementazioni esistenti non conformi (è illegale usare quelle funzioni dal gestore di segnali, per esempio).

L'IO basato su completamento e su base prontezza non è correlato solo ai file. L'IO basato sul completamento è quando l'utente riceve una notifica sul completamento dell'intera operazione, mentre con l'utente dell'API basato sulla prontezza viene solo notificato che la lettura o la scrittura possono essere eseguite senza bloccare.

L'IO basato sul completamento è più generale e può funzionare meglio con i thread. L'IO basato su Readiness può essere utilizzato solo con IO non bloccanti e quindi non può essere utilizzato con i file.

L'IO basato sul completamento può essere implementato usando l'IO basato sulla prontezza, ma non è vero il contrario. Quindi se la libreria fornisce un IO basato sulla prontezza che funziona con i socket, non può fornire la stessa interfaccia per i file.

Su Windows l'API asincrona nativa più efficiente è basata sul completamento e si chiama I / O sovrapposti . I sistemi di tipo Unix utilizzano l'IO basato sulla prontezza primaria: epoll , kqueue , / dev / sondaggio .

Linux ha la possibilità di ricevere una notifica di completamento che può arrivare a eventfd . Ma non ha senso quando ci sono così tante limitazioni.

Penso che FreeBSD implementi l'IO asincrono POSIX nel kernel e ti consenta di ricevere notifiche di completamento tramite kqueue . Non sono sicuro di quanto sia bello.

    
risposta data 24.01.2018 - 19:17
fonte
1

Non c'è nulla di particolarmente interessante sull'I / O dei file da un punto di vista asincrono. Non si può nemmeno parallelizzare bene nel caso generale, perché il canale I / O presenta inevitabilmente limitazioni intrinseche che non possono essere superate con la parallelizzazione. Alcuni schemi di parallelizzazione danneggeranno in realtà le prestazioni sui supporti che si prestano più facilmente a letture e scritture consecutive, come le unità a fuso.

Di conseguenza, è meglio trattare tale I / O come un payload, non una funzione speciale di async. Una volta presa questa decisione progettuale, sei libero di scrivere una libreria asincrona che funziona con qualsiasi payload, non solo I / O di file. Questa disposizione non dovrebbe essere sorprendente; è semplicemente un'altra forma di Separazione delle preoccupazioni.

Considera questo: qualsiasi metodo sincrono può essere reso asincrono utilizzando meccanismi come callback, promesse, thread, continuazioni, ecc.

    
risposta data 24.01.2018 - 06:32
fonte

Leggi altre domande sui tag