web-dev-qa-db-fra.com

Tamponné vs non tamponné IO

J'ai appris que par défaut les E/S dans les programmes sont tamponnées, c'est-à-dire qu'elles sont servies à partir d'un stockage temporaire vers le programme demandeur. Je comprends que la mise en mémoire tampon améliore les performances IO (peut-être en réduisant les appels système). J'ai vu des exemples de désactivation de la mise en mémoire tampon, comme setvbuf en C. Quelle est la différence entre les deux modes et quand faut-il utiliser l'un sur l'autre?

68
sud03r

Vous voulez une sortie sans tampon chaque fois que vous voulez vous assurer que la sortie a été écrite avant de continuer. Un exemple est l'erreur standard sous une bibliothèque d'exécution C - elle est généralement non tamponnée par défaut. Comme les erreurs sont (espérons-le) peu fréquentes, vous voulez les connaître immédiatement. D'un autre côté, la sortie standard is est tamponnée simplement parce que l'on suppose qu'il y aura beaucoup plus de données qui la traverseront.

Un autre exemple est une bibliothèque de journalisation. Si vos messages de journal sont conservés dans des tampons de votre processus et que votre processus vide le noyau, il y a de très bonnes chances que la sortie ne soit jamais écrite.

De plus, ce ne sont pas seulement les appels système qui sont minimisés, mais aussi les E/S disque. Disons qu'un programme lit un fichier un octet à la fois. Avec une entrée sans tampon, vous irez sur le disque (relativement très lent) pour chaque octet même s'il doit probablement lire dans un bloc entier de toute façon (le matériel du disque lui-même peut avoir des tampons mais vous sortez toujours vers le contrôleur de disque qui va être plus lent que l'accès en mémoire).

En mettant en mémoire tampon, le bloc entier est lu dans le tampon à la fois, puis les octets individuels vous sont livrés à partir de la zone de tampon (en mémoire, incroyablement rapide).

Gardez à l'esprit que la mise en mémoire tampon peut prendre plusieurs formes, comme dans l'exemple suivant:

+-------------------+-------------------+
| Process A         | Process B         |
+-------------------+-------------------+
| C runtime library | C runtime library | C RTL buffers
+-------------------+-------------------+
|               OS caches               | Operating system buffers
+---------------------------------------+
|      Disk controller hardware cache   | Disk hardware buffers
+---------------------------------------+
|                   Disk                |
+---------------------------------------+
108
paxdiablo

Vous voulez une sortie sans tampon lorsque vous avez déjà une grande séquence d'octets prête à écrire sur le disque et que vous voulez éviter une copie supplémentaire dans un deuxième tampon au milieu.

Les flux de sortie mis en mémoire tampon accumuleront les résultats d'écriture dans une mémoire tampon intermédiaire, ne les envoyant au système de fichiers du système d'exploitation que lorsque suffisamment de données se seront accumulées (ou flush() est demandé). Cela réduit le nombre d'appels du système de fichiers. Étant donné que les appels du système de fichiers peuvent coûter cher sur la plupart des plates-formes (par rapport à short memcpy), la sortie en mémoire tampon est un gain net lors de l'exécution d'un grand nombre de petites écritures. La sortie sans tampon est généralement meilleure lorsque vous avez déjà de gros tampons à envoyer - la copie vers un tampon intermédiaire ne réduira pas davantage le nombre d'appels du système d'exploitation et introduit un travail supplémentaire.

La sortie sans tampon a rien pour garantir que vos données atteignent le disque; cette fonctionnalité est fournie par flush(), et fonctionne à la fois sur les flux tamponnés et non tamponnés. Non tamponné IO ne garantissent pas que les données ont atteint le disque physique - le système de fichiers du système d'exploitation est libre de conserver une copie de vos données indéfiniment, sans jamais l'écrire sur le disque, si Il n'est nécessaire de le valider sur le disque que lorsque vous appelez flush(). (Notez que close() appellera flush() en votre nom).

28
Aaron