2012-05-12 16 views
16

Parece haber mucha confusión con respecto al propósito de los dos argumentos 'tamaño' y 'contar' en fwrite(). Estoy tratando de averiguar que será más rápido -fwrite() - efecto de tamaño y cuenta en el rendimiento

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, podría pasar a probar y usar la que da mejores resultados, pero el problema es que el código está destinado a MUCHAS plataformas.

Así,

  • ¿Cómo puedo obtener una respuesta definitiva a la que es mejor a través de plataformas?

  • ¿La lógica de implementación de fwrite() varía de una plataforma a otra?

Sé que existen preguntas similares (What is the rationale for fread/fwrite taking size and count as arguments?, Performance of fwrite and write size), pero entienden que esta es una cuestión diferente sobre el mismo tema. Las respuestas en preguntas similares no son suficientes en este caso.

+0

Acabo de hacer algunas pruebas en OS-X, escribiendo diez archivos de 100MB, y no hubo diferencia entre el orden de los parámetros, o al usar write (2) en lugar de fwrite. En cuanto a otras plataformas, no puedo decir. –

Respuesta

13

El rendimiento no debe depender de ninguna manera, ya que cualquiera que implemente fwrite multiplicará el tamaño y el conteo para determinar la cantidad de E/S que se debe realizar.

Ejemplo de ello es la implementación de libc de FreeBSD de fwrite.c, que en su totalidad se lee (incluir directivas elididas):

/* 
* 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); 
} 
+1

Ejecuté pruebas en varias plataformas y miré el código fuente de fwrite para algunos otros, sin diferencia de rendimiento en ninguno de ellos. ¡Gracias! –

12

El propósito de dos argumentos se vuelve más clara, si considera Ther valor de retorno, que es el recuento de objetos exitosamente escrito/lectura a/de la corriente: depende

fwrite(src, 1, 50000, dst); // will return 50000 
fwrite(src, 50000, 1, dst); // will return 1 

la velocidad puede ser puesta en práctica, aunque, no espero ninguna considerabl e diferencia.

+2

+1: en particular, el primero fallará si solo obtiene 49999 bytes (devuelve 0); el segundo devolverá 49999 si ese es el número de bytes que lee. Entonces, si sus datos son rígidamente 50,000 bytes, no importa lo que usted use. Si sus datos no son rígidos, pero podrían ser más cortos, entonces necesita la opción más flexible. –

+0

Uso erróneamente 'fread' en lugar de' fwrite', pero el mismo principio se aplica por ambos lados. –

+0

@ AlešKotnik No dude en editar su respuesta. – Jens

2

me gustaría señalarle a my question, que terminó exponiendo una diferencia interesante entre el rendimiento llamando y llamando fwrite vez fwrite varias veces para escribir un archivo "en pedazos".

Mi problema es que hay un error en la implementación de fwrite de Microsoft, por lo que los archivos de más de 4 GB no pueden escribirse en una sola llamada (se cuelga en fwrite). Así que tuve que solucionar esto escribiendo el archivo en fragmentos, llamando al fwrite en un bucle hasta que los datos se escribieron por completo. Descubrí que este último método siempre regresa más rápido que la llamada única fwrite.

Estoy en Windows 7 x64 con 32 GB de RAM, lo que hace que el caché de escritura sea bastante agresivo.

Cuestiones relacionadas