Utilizzo della memoria IO asincrono rispetto a completamento?

11

Stavo guardando questo talk sull'implementazione di IO asincrono in Rust e Carl menziona due potenziali modelli. Disponibilità e completamento.

Modello di prontezza:

  • dici al kernel che vuoi leggere da un socket
  • fai altre cose per un po '...
  • il kernel ti dice quando il socket è pronto
  • leggi (inserisci un buffer)
  • fai tutto il necessario
  • libera il buffer (avviene automaticamente con Rust)

Modello di completamento:

  • allocate un buffer per il kernel da riempire
  • fai altre cose per un po '...
  • il kernel ti dice quando il buffer è stato riempito
  • fai tutto il necessario con i dati
  • libera il buffer

Nell'esempio di Carl di usare il modello di prontezza si può scorrere le prese pronte per riempire e liberare un buffer globale che fa sembrare che utilizzerebbe molto meno memoria.

Ora le mie ipotesi:

Sotto il cofano (nello spazio del kernel) quando un socket è detto "pronto", i dati esistono già. È entrato nel socket sulla rete (o da qualsiasi luogo) e il sistema operativo si sta trattenendo sui dati.

Non è che l'allocazione di memoria magicamente non avvenga nel modello di prontezza. È solo che il sistema operativo lo sta estrapolando da te. Nel modello di completamento, il sistema operativo ti chiede di allocare la memoria prima che i dati entrino effettivamente ed è ovvio che cosa sta succedendo.

Ecco la mia versione modificata del Modello di competenza:

  • dici al kernel che vuoi leggere da un socket
  • fai altre cose per un po '...
  • EMENDAMENTO: i dati arrivano al sistema operativo (un po 'di spazio nella memoria del kernel)
  • il kernel dice che il socket è pronto
  • leggi (riempi un altro buffer separato dal buffer del kernel di abover (o ottieni un puntatore ad esso?))
  • fai tutto il necessario
  • libera il buffer (avviene automaticamente con Rust)

/ Le mie ipotesi

Mi è sempre piaciuto mantenere il programma dello spazio utente di piccole dimensioni, ma volevo solo qualche chiarimento su ciò che, in realtà, sta accadendo qui. Non vedo che un modello usi intrinsecamente meno memoria o supporti un livello più alto di IO simultaneo. Mi piacerebbe sentire pensieri e una spiegazione più approfondita di questo.

    
posta kjs3 17.08.2015 - 18:51
fonte

2 risposte

5

Nel consumo di memoria del Modello di readiness è proporzionale alla quantità di dati non utilizzati dall'applicazione.

Nel modello di completamento il consumo di memoria è proporzionale alla quantità di chiamate socket in sospeso.

Se ci sono molti socket che sono per lo più inattivi, il modello Readiness consuma meno memoria.

C'è una soluzione semplice per il modello di completamento: avviare una lettura di 1 byte. Questo consuma solo un piccolo buffer. Al termine della lettura, viene emessa un'altra lettura (forse sincrona) che ottiene il resto dei dati.

In alcune lingue il modello di completamento è estremamente semplice da implementare. La considero una buona scelta predefinita.

    
risposta data 20.08.2015 - 21:02
fonte
1

In the Completion model, the OS is asking you to allocate memory before data actually flows in and it's obvious what's happening.

Ma cosa succede se arrivano più dati di quanti ne hai stanziati? Il kernel deve ancora allocare il proprio buffer in modo da non rilasciare i dati. (Ad esempio, questo è il motivo per cui il trucco di lettura a 1 byte menzionato nella risposta di usr funziona.)

Il compromesso è che mentre il modello di completamento consuma più memoria, può anche (a volte) fare meno operazioni di copia, perché mantenere il buffer intorno significa che l'hardware può direttamente o fuori da esso. Sospetto anche (ma sono meno sicuro) che il Modello di completamento tenda a fare l'operazione di copia effettiva (quando esiste) su un altro thread, almeno per IOCP di Windows, mentre il Modello di Readiness lo fa come parte della percentuale di non bloccoread() o write() call.

    
risposta data 18.01.2017 - 07:59
fonte

Leggi altre domande sui tag