2012-05-09 11 views
50

In dispersione e riuniscono (vale a dire readv e writev), Linux legge in più buffer e scrive da più buffer.Linux: Quando usare scatter/gather IO (readv, writev) contro un buffer di grandi dimensioni con fread

Se dico, ho un vettore di 3 buffer, posso usare readv, O posso usare un singolo buffer, che è di dimensioni combinate di 3 buffer e fare fread.

Quindi, sono confuso: per quali casi bisognerebbe sparpagliare/raccogliere e quando dovrebbe essere utilizzato un unico grande buffer?

risposta

83

La comodità principale offerto da readv, writev è:

  1. Esso permette di lavorare con blocchi non contigui di dati. Ad esempio, i buffer hanno bisogno di non essere parte di un array, ma allocati separatamente.
  2. L'I/O è "atomico". Ad esempio, se si fa un writev, tutti gli elementi nel vettore verranno scritti in un'operazione contigua e le scritture eseguite da altri processi non si verificheranno tra di essi.

ad es. per esempio, i dati sono naturalmente segmentato, e proviene da fonti diverse:

struct foo *my_foo; 
struct bar *my_bar; 
struct baz *my_baz; 

my_foo = get_my_foo(); 
my_bar = get_my_bar(); 
my_baz = get_my_baz(); 

Ora, tutti e tre i 'buffer' sono non un unico grande blocco contiguo. Ma vuoi scriverli in modo contiguo in un file, per qualsiasi motivo (ad esempio, sono campi in un'intestazione di file per un formato di file).

Se si utilizza write devi scegliere tra:

  1. li Copiare in un unico blocco di memoria utilizzando, per esempio, memcpy (overhead), seguito da un singolo write chiamata. Quindi la scrittura sarà atomica.
  2. Effettuare tre chiamate separate a write (overhead). Inoltre, le chiamate write da altri processi possono intersperse tra queste scritture (non atomiche).

Se si utilizza writev invece, è tutto buono:

  1. Si fanno esattamente una chiamata di sistema, e non memcpy per fare un singolo buffer da tre.
  2. Inoltre, i tre buffer sono scritti atomicamente, come una scrittura di blocco. cioè se anche altri processi scrivono, allora queste scritture non verranno tra le scritture dei tre vettori.

Così si farebbe qualcosa di simile:

struct iovec iov[3]; 

iov[0].iov_base = my_foo; 
iov[0].iov_len = sizeof (struct foo); 
iov[1].iov_base = my_bar; 
iov[1].iov_len = sizeof (struct bar); 
iov[2].iov_base = my_baz; 
iov[2].iov_len = sizeof (struct baz); 

bytes_written = writev (fd, iov, 3); 

Fonti:

  1. http://pubs.opengroup.org/onlinepubs/009604499/functions/writev.html
  2. http://linux.die.net/man/2/readv
+3

Nel 'Linux Sistema programming' libro, dicono' readv o writev può verificarsi con qualsiasi gli errori delle chiamate di sistema read() e write() e, dopo aver ricevuto tali errori, impostano gli stessi codici errno. Quindi readv restituirà 'EINTR'? O cosa succederà a un segnale che si verifica tra la lettura atomica di readv? sarà ignorato o accodato. – nmxprime

+0

@nmxprime se il segnale arriva durante 'readv()' o 'writev()', queste syscalls (a seconda di SA_RESTART) restituiranno meno byte di quanto richiesto. – socketpair

+0

Posso scrivere il buffer non contiguo nel file in modo non contiguo e non come un blocco intero? – RAFA

Problemi correlati