In computing, vectored I/O, also known as scatter/gather I/O, is a method of input and output by which a single procedure call sequentially reads data from multiple buffers and writes it to a single data stream (gather), or reads data from a data stream and writes it to multiple buffers (scatter), as defined in a vector of buffers. Scatter/gather refers to the process of gathering data from, or scattering data into, the given set of buffers. Vectored I/O can operate synchronously or asynchronously. The main reasons for using vectored I/O are efficiency and convenience.
Vectored I/O has several potential uses:
Standards bodies document the applicable functions readv
[1] and writev
[2] in POSIX 1003.1-2001 and the Single UNIX Specification version 2. The Windows API has analogous functions ReadFileScatter
and WriteFileGather
; however, unlike the POSIX functions, they require the alignment of each buffer on a memory page. [3] Winsock provides separate WSASend
and WSARecv
functions without this requirement.
While working directly with a vector of buffers can be significantly harder than working with a single buffer, using higher-level APIs [4] for working efficiently can mitigate the difficulties.
The following example in the C programming language prints "Hello, Wikipedia Community!" to the standard output. Each word is saved into a single buffer and with only one call to writev()
, all buffers are printed to the standard output.
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/uio.h>intmain(intargc,char*argv[]){constcharbuf1[]="Hello, ";constcharbuf2[]="Wikipedia ";constcharbuf3[]="Community!\n";structiovecbufs[]={{.iov_base=(void*)buf1,.iov_len=strlen(buf1)},{.iov_base=(void*)buf2,.iov_len=strlen(buf2)},{.iov_base=(void*)buf3,.iov_len=strlen(buf3)},};if(writev(STDOUT_FILENO,bufs,sizeof(bufs)/sizeof(bufs[0]))==-1){perror("writev()");exit(EXIT_FAILURE);}returnEXIT_SUCCESS;}
Rust provides the write_vectored
method on the Write
trait. [5]
usestd::io::IoSlice;usestd::io::prelude::*;usestd::fs::File;fnmain()-> std::io::Result<()>{letdata1=[1;8];letdata2=[15;8];letio_slice1=IoSlice::new(&data1);letio_slice2=IoSlice::new(&data2);letmutbuffer=File::create("foo.txt")?;// Writes some prefix of the byte string, not necessarily all of it.buffer.write_vectored(&[io_slice1,io_slice2])?;Ok(())}