2012-05-12 12 views
16

Sembra esserci molta confusione riguardo allo scopo dei due argomenti "dimensione" e "conteggio" in fwrite(). Sto cercando di capire quale sarà più veloce -fwrite() - l'effetto della dimensione e il conteggio delle prestazioni

fwrite(source, 1, 50000, destination); 

o

fwrite(source, 50000, 1, destination); 

Questa è una decisione importante nel mio codice come questo comando sarà eseguito milioni di volte.

Ora, potrei semplicemente saltare a testare e utilizzare quello che dà risultati migliori, ma il problema è che il codice è destinato a MOLTE piattaforme.

Quindi,

  • come posso ottenere una risposta definitiva alla quale è meglio tra le piattaforme?

  • La logica di implementazione di fwrite() varia da piattaforma a piattaforma?

mi rendo conto ci sono domande simili (What is the rationale for fread/fwrite taking size and count as arguments?, Performance of fwrite and write size), ma capisco che questa è una domanda diversa per quanto riguarda lo stesso problema. Le risposte a domande simili non sono sufficienti in questo caso.

+0

Ho appena eseguito alcuni test su OS-X, scrivendo dieci file da 100 MB e non c'era alcuna differenza tra l'ordine dei parametri o quando si utilizza write (2) anziché fwrite. Per quanto riguarda altre piattaforme, non posso dire. –

risposta

13

Le prestazioni non devono dipendere in alcun modo, poiché chiunque implementa il metodo Fwrite moltiplicherà le dimensioni e il conteggio per determinare la quantità di I/O da eseguire.

Questo è esemplificata dalla implementazione libc di FreeBSD di fwrite.c, che nella sua interezza legge (includere direttive elise):

/* 
* 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

Ho eseguito test su diverse piattaforme e ho esaminato il codice sorgente di Fwrite per alcuni altri, senza alcuna differenza di prestazioni in nessuno di essi. Grazie! –

12

Lo scopo della due argomenti si fa più chiara, se si considera ther valore di ritorno, che è il conteggio degli oggetti con successo scritte/lettura da/per il flusso:

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

la velocità potrebbe essere a carico di attuazione, anche se, non mi aspetto alcun considerabl e differenza.

+2

+1: In particolare, il primo fallisce se ottiene solo 49999 byte (restituendo 0); il secondo restituirà 49999 se questo è il numero di byte letti. Quindi, se i tuoi dati sono rigidamente di 50.000 byte, non importa in alcun modo che usi. Se i tuoi dati non sono rigidi ma potrebbero essere più brevi, allora hai bisogno dell'opzione più flessibile. –

+0

Uso erroneamente 'fread' invece di' fwrite' ma lo stesso principio si applica comunque. –

+0

@ AlešKotnik Sentiti libero di modificare la tua risposta. – Jens

2

mi piacerebbe puntare a my question, che ha finito per esporre una differenza di prestazioni interessante tra chiamare fwrite una sola volta e chiamando fwrite più volte per scrivere un file "in blocchi".

Il mio problema era che c'è un bug nell'implementazione di fwrite da parte di Microsoft, quindi file più grandi di 4 GB non possono essere scritti in una sola chiamata (si blocca su fwrite). Quindi ho dovuto aggirare questo problema scrivendo il file in blocchi, chiamando fwrite in un ciclo finché i dati non sono stati scritti completamente. Ho scoperto che quest'ultimo metodo ritorna sempre più veloce della singola chiamata fwrite.

Sono in Windows 7 x64 con 32 GB di RAM, il che rende la cache di scrittura piuttosto aggressiva.

Problemi correlati