txt manejo lenguaje leer guardar fscanf fprintf ejercicios datos binarios archivos archivo c linux

manejo - ¿Por qué la función fwrite libc es más rápida que la función de escritura syscall?



guardar y leer datos en un archivo.txt en c (3)

Después de proporcionar el mismo programa que lee un archivo de entrada generado aleatoriamente y repite la misma cadena que leyó en una salida. La única diferencia es que en un lado estoy proporcionando los métodos de lectura y escritura de Linux syscalls, y en el otro lado estoy usando fread / fwrite.

Al sincronizar mi aplicación con una entrada de 10Mb de tamaño y enviarla a / dev / null, y asegurándome de que el archivo no se almacene en la caché, descubrí que el código de libc es más rápido en una escala GRANDE cuando se utilizan buffers muy pequeños caso).

Aquí está mi salida del tiempo, usando fwrite:

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

Y usando el syscall escriba:

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

La única posibilidad en la que puedo pensar es que libc internamente ya está almacenando en búfer mi entrada ... Desafortunadamente, no pude encontrar mucha información en la web, así que tal vez los gurús de aquí puedan ayudarme.


Al sincronizar mi aplicación con una entrada de 10Mb de tamaño y enviarla a / dev / null, y asegurándome de que el archivo no esté en caché, he descubierto que el frwite de libc es más rápido en una escala GRANDE cuando se utilizan buffers muy pequeños (1 byte en caso).

fwrite funciona en secuencias, que están en búfer. Por lo tanto, muchos búferes pequeños serán más rápidos porque no ejecutarán una llamada de sistema costosa hasta que el búfer se llene (o lo vacíe o cierre el flujo). Por otro lado, los búferes pequeños que se envían para write ejecutarán una costosa llamada al sistema para cada búfer ; ahí es donde se pierde la velocidad. Con un búfer de flujo de 1024 bytes y escritura de búferes de 1 byte, usted está viendo 1024 llamadas de write por cada kilobyte , en lugar de 1024 llamadas de letra de escritura que se convierten en una write ; ¿ve la diferencia?

Para los búferes grandes, la diferencia será pequeña, porque habrá menos almacenamiento en búfer y, por lo tanto, habrá un número más consistente de llamadas al sistema entre write y write .

En otras palabras, fwrite(3) es solo una rutina de biblioteca que recopila resultados en fragmentos y luego llama a write(2) . Ahora, write(2) , es una llamada al sistema que atrapa el kernel . Ahí es donde realmente ocurre la E / S. Hay algo de sobrecarga por simplemente llamar al kernel, y luego está el tiempo necesario para escribir algo. Si usa búferes grandes, encontrará que write(2) es más rápido porque eventualmente tiene que ser llamado de todos modos, y si está escribiendo una o más veces por escritura, la sobrecarga de almacenamiento en búfer de Fwrite es solo eso: más sobrecarga.

Si desea obtener más información al respecto, puede consultar este documento , que explica las secuencias de E / S estándar.



write (2) es la operación fundamental del kernel.

fwrite (3) es una función de biblioteca que agrega almacenamiento en búfer en la parte superior de write (2).

Para los recuentos de bytes pequeños (p. Ej., Línea a la vez), fwrite (3) es más rápido, debido a la sobrecarga por solo hacer una llamada al kernel.

Para grandes recuentos de bytes (bloque de E / S), write (2) es más rápido, ya que no se preocupa por el almacenamiento en búfer y tiene que llamar al núcleo en ambos casos.

Si observa la fuente de cp (1), no verá ningún búfer.

Finalmente, hay una última consideración: ISO C vs Posix. Las funciones de la biblioteca con búfer como fwrite se especifican en ISO C, mientras que las llamadas del kernel como write son Posix. Si bien muchos sistemas afirman ser compatibles con Posix, especialmente cuando se trata de calificar para contratos gubernamentales, en la práctica es específico de los sistemas similares a Unix. Por lo tanto, las operaciones con búfer son más portátiles. Como resultado, un cp Linux ciertamente usará la write pero un programa de C que tiene que funcionar en varias plataformas puede tener que usar fwrite.