2009-09-01 10 views
20

Après avoir fourni le même programme qui lit un fichier d'entrée généré de manière aléatoire et fait écho à la même chaîne qu'il a lue sur une sortie. La seule différence est que, d'un côté, je fournis les méthodes de lecture et d'écriture à partir de syscalls linux, et de l'autre côté j'utilise fread/fwrite. En programmant mon application avec une taille de 10Mb et en la renvoyant à/dev/null, et en m'assurant que le fichier n'est pas mis en cache, j'ai trouvé que le fwrite de libc est plus rapide avec une grande échelle en utilisant de très petits tampons (1 octet dans le cas).Pourquoi la fonction fwrite libc est plus rapide que la fonction d'écriture syscall?

Voici ma sortie de temps, en utilisant fwrite:

real 0m0.948s 
user 0m0.780s 
sys  0m0.012s 

Et en utilisant le syscall écrire:

real 0m8.607s 
user 0m0.972s 
sys  0m7.624s 

La seule possibilité que je peux penser est que l'intérieur libc est déjà mise en mémoire tampon mon entrée ... Malheureusement, je ne pouvais pas trouver autant d'informations sur le web, alors peut-être que les gourous ici pourraient m'aider.

+4

"interne libc est déjà en train de mettre en mémoire tampon mon entrée". C'est exactement ce qu'il fait. Vous pouvez probablement même lire le code source de libc si vous le souhaitez, et voir exactement comment cela se passe. – kquinn

Répondre

29

Calendrier ma demande avec une entrée de 10Mo en taille et en écho à /dev/null, et en vous assurant le fichier en pas mises en cache, j'ai trouvé que frwite de libc est plus rapide par un grand échelle lorsque en utilisant de très petits tampons (1 octet dans cas).

fwrite fonctionne sur les flux qui sont tamponnés. Par conséquent, de nombreux petits tampons seront plus rapides car ils n'effectueront pas un appel système coûteux jusqu'à ce que le tampon se remplisse (ou que vous le purgiez ou que vous fermiez le flux). D'autre part, les petits tampons étant envoyés à write exécutera un appel système coûteux pour chaque tampon - c'est là que vous perdez la vitesse. Avec un tampon de flux de 1024 octets, et l'écriture de tampons de 1 octet, vous regardez 1024 write appels pour chaque kilobyte, plutôt que 1024 fwrite appels se transformant en un write - voir la différence?

Pour les gros tampons, la différence sera faible, car il y aura moins de mise en mémoire tampon, et donc un nombre plus cohérent d'appels système entre fwrite et write. En d'autres termes, fwrite(3) est simplement une routine de bibliothèque qui collecte la sortie en blocs, puis appelle write(2). Maintenant, write(2), est un appel système dont pièges dans le noyau. C'est là que les E/S arrivent. Il y a des frais généraux pour simplement appeler le noyau, et puis il y a le temps qu'il faut pour écrire quelque chose. Si vous utilisez des tampons volumineux, vous constaterez que write(2) est plus rapide car il doit éventuellement être appelé de toute façon, et si vous écrivez une ou plusieurs fois par fwrite alors le surcoût de tamponnage fwrite est juste cela: plus de surcharge.

Si vous voulez en savoir plus à ce sujet, vous pouvez consulter this document, qui explique les flux d'E/S standard.

14

write (2) est l'opération du noyau fondamental.

fwrite (3) est une fonction de bibliothèque qui ajoute un tampon au-dessus de write (2).

Pour les comptages d'octets de petite taille (par exemple, une ligne à la fois), fwrite (3) est plus rapide, en raison du temps système nécessaire pour effectuer un appel de noyau.

Pour les comptages d'octets de grande taille (E/S de bloc), write (2) est plus rapide, car il ne dérange pas la mise en mémoire tampon et vous devez appeler le noyau dans les deux cas.

Si vous regardez la source à cp (1), vous ne verrez aucune mise en mémoire tampon. Enfin, il y a une dernière considération: ISO C contre Posix. Les fonctions de bibliothèque mises en mémoire tampon comme fwrite sont spécifiées dans ISO C tandis que les appels de noyau comme write sont Posix. Bien que de nombreux systèmes prétendent être compatibles avec Posix, en particulier lorsqu'ils tentent de se qualifier pour des contrats gouvernementaux, dans la pratique, ils sont spécifiques aux systèmes de type Unix. Ainsi, les opérations tamponnées sont plus portables. Par conséquent, un cp de Linux utilisera certainement write mais un programme C qui doit fonctionner sur plusieurs plates-formes devra peut-être utiliser fwrite.

+0

J'ai récemment eu une interview et j'ai donné le même raisonnement sur la différence b/w écrire et écrire et la réponse que j'ai eu était, "vous la connaissance de cette différence est complètement faux" !! L'intervieweur m'a semblé très arrogant. Pourtant, je voulais juste confirmer, s'il y a une autre différence entre les appels faits par glibc et les appels faits directement au noyau? –

+0

@PK, j'ai mis à jour ma réponse ... – DigitalRoss

Questions connexes