2012-04-25 18 views
8

Sto utilizzando la funzione chiamata fwrite() per scrivere dati su una pipe su Linux.Informazioni sul comportamento di buffering di fwrite()

In precedenza, fwrite() veniva chiamato per piccoli blocchi di dati (in media 20 byte) ripetutamente e il buffering veniva lasciato a fwrite(). Strace sul processo ha mostrato che 4096 byte di dati venivano scritti alla volta.

Si è scoperto che questo processo di scrittura era il collo di bottiglia del mio programma. Così ho deciso di memorizzare i dati nel mio codice in blocchi di 64 KB e quindi scrivere l'intero blocco alla volta utilizzando fwrite(). Ho usato setvbuf() per impostare il puntatore FILE * su "Nessun buffer".

Il miglioramento delle prestazioni non è stato così significativo come mi aspettavo.

Ancora più importante, l'output strace ha mostrato che i dati venivano ancora scritti 4096 byte alla volta. Qualcuno può spiegarmi questo comportamento? Se sto chiamando fwrite() con 64 KB di dati, perché scrive solo 4096 byte alla volta?

Esiste un'alternativa a fwrite() per la scrittura di dati su una pipe utilizzando un puntatore FILE *?

+0

Puoi mostrarci il codice? – tuxuday

+1

@Shailesh_Tainwala: potresti scrivere il tuo codice in C++, ma questa è una domanda c piuttosto che C++. 'fwrite()' è una funzione c, non una funzione C++. Ho aggiunto un tag c alla tua domanda in modo da poter ottenere un pubblico più ampio. –

risposta

8

Il 4096 deriva dal macchinario Linux che è alla base delle tubazioni. Ci sono due posti in cui si verifica. Uno è la capacità della pipeline. La capacità è una pagina di sistema su versioni precedenti di Linux, che è 4096 byte su una macchina i386 a 32 bit. (Su versioni più moderne di Linux la capacità è 64K.)

L'altro punto in cui si verifica il problema di 4096 byte è nella costante definita PIPE_BUF, il numero di byte che è garantito che vengano trattati in modo atomico. Su Linux questo è 4096 byte. Che cosa significa questo limite dipende dal fatto che la pipeline sia stata impostata su blocco o non blocco. Fai un man -S7 pipe per tutti i dettagli cruenti.

Se si sta tentando di scambiare enormi volumi di dati ad alta velocità, si potrebbe voler ripensare l'uso dei tubi. Sei su una scatola Linux, quindi la memoria condivisa è un'opzione. È possibile utilizzare le pipe per inviare quantità relativamente piccole di dati come meccanismo di segnalazione.

+0

Un'altra opzione possibile solo per Linux sarebbe utilizzare open() e splice() invece di fwrite(). –

4

Se si desidera modificare il comportamento buffering, è necessario farlo subito dopo la fopen (o prima di ogni I/O, per gli standard di filehandle stdin, stdout, stderr). Inoltre, non si desidera disabilitare il buffering e provare a gestire il buffer da soli; piuttosto, specifica il tuo buffer 64K su setvbuf in modo che possa essere usato correttamente.

Se si desidera gestire manualmente il buffering, non utilizzare stdio; utilizzare le chiamate di livello inferiore open, write e close.

Problemi correlati