c - online - tag id3
fwrite()-efecto de tamaƱo y cuenta en el rendimiento (3)
Parece que hay mucha confusión con respecto al propósito de los dos argumentos ''tamaño'' y ''recuento'' en fwrite (). Estoy tratando de averiguar cuál será más rápido -
fwrite(source, 1, 50000, destination);
o
fwrite(source, 50000, 1, destination);
Esta es una decisión importante en mi código, ya que este comando se ejecutará millones de veces.
Ahora, simplemente podría pasar a la prueba y usar la que da mejores resultados, pero el problema es que el código está destinado a MUCHAS plataformas.
Asi que,
¿Cómo puedo obtener una respuesta definitiva a cuál es mejor en todas las plataformas?
¿La lógica de implementación de fwrite () variará de plataforma a plataforma?
Me doy cuenta de que hay preguntas similares ( ¿cuál es la razón para que fread / fwrite tome tamaño y cuente como argumentos?, Rendimiento de fwrite y escriba ), pero entiendo que esta es una pregunta diferente con respecto al mismo problema. Las respuestas en preguntas similares no son suficientes en este caso.
El propósito de dos argumentos se vuelve más claro, si considera el valor de retorno , que es el recuento de objetos escritos / leídos con éxito a / desde la secuencia:
fwrite(src, 1, 50000, dst); // will return 50000
fwrite(src, 50000, 1, dst); // will return 1
La velocidad puede depender de la implementación, aunque no espero ninguna diferencia considerable.
El rendimiento no debe depender de ninguna de las dos formas, ya que cualquiera que implemente fwrite multiplicaría el tamaño y el conteo para determinar la cantidad de E / S que debe hacer.
Esto se ejemplifica mediante la implementación libc de FreeBSD de fwrite.c
, que en su totalidad lee (incluyen directivas eluidas):
/*
* Write `count'' objects (each size `size'') from memory to the given file.
* Return the number of whole objects written.
*/
size_t
fwrite(buf, size, count, fp)
const void * __restrict buf;
size_t size, count;
FILE * __restrict fp;
{
size_t n;
struct __suio uio;
struct __siov iov;
/*
* ANSI and SUSv2 require a return value of 0 if size or count are 0.
*/
if ((count == 0) || (size == 0))
return (0);
/*
* Check for integer overflow. As an optimization, first check that
* at least one of {count, size} is at least 2^16, since if both
* values are less than that, their product can''t possible overflow
* (size_t is always at least 32 bits on FreeBSD).
*/
if (((count | size) > 0xFFFF) &&
(count > SIZE_MAX / size)) {
errno = EINVAL;
fp->_flags |= __SERR;
return (0);
}
n = count * size;
iov.iov_base = (void *)buf;
uio.uio_resid = iov.iov_len = n;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
FLOCKFILE(fp);
ORIENT(fp, -1);
/*
* The usual case is success (__sfvwrite returns 0);
* skip the divide if this happens, since divides are
* generally slow and since this occurs whenever size==0.
*/
if (__sfvwrite(fp, &uio) != 0)
count = (n - uio.uio_resid) / size;
FUNLOCKFILE(fp);
return (count);
}
Me gustaría señalarle mi pregunta , que terminó exponiendo una interesante diferencia de rendimiento entre llamar a fwrite
una vez y llamar a fwrite
varias veces para escribir un archivo "en trozos".
Mi problema fue que hay un error en la implementación de fwrite de Microsoft, por lo que los archivos de más de 4 GB no se pueden escribir en una llamada (se cuelga en fwrite
). Así que tuve que solucionar esto escribiendo el archivo en trozos, llamando a fwrite
en un bucle hasta que los datos se escribieron por completo. Encontré que este último método siempre devuelve más rápido que la única llamada fwrite
.
Estoy en Windows 7 x64 con 32 GB de RAM, lo que hace que el almacenamiento en caché de escritura sea bastante agresivo.