Input/output method in computing From Wikipedia, the free encyclopedia
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>
int main(int argc, char *argv[])
{
const char buf1[] = "Hello, ";
const char buf2[] = "Wikipedia ";
const char buf3[] = "Community!\n";
struct iovec bufs[] = {
{ .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);
}
return EXIT_SUCCESS;
}
Rust provides the write_vectored
method on the Write
trait.[5]
use std::io::IoSlice;
use std::io::prelude::*;
use std::fs::File;
fn main() -> std::io::Result<()> {
let data1 = [1; 8];
let data2 = [15; 8];
let io_slice1 = IoSlice::new(&data1);
let io_slice2 = IoSlice::new(&data2);
let mut buffer = File::create("foo.txt")?;
// Writes some prefix of the byte string, not necessarily all of it.
buffer.write_vectored(&[io_slice1, io_slice2])?;
Ok(())
}
Seamless Wikipedia browsing. On steroids.