Vectored I/O

{{short description|Input/output method in computing}}

{{About|the I/O method|the vector addressing type|gather/scatter (vector addressing)}}

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:

  • Atomicity: if the particular vectored I/O implementation supports atomicity, a process can write into or read from a set of buffers to or from a file without risk that another thread or process might perform I/O on the same file between the first process' reads or writes, thereby corrupting the file or compromising the integrity of the input
  • Concatenating output: an application that wants to write non-sequentially placed data in memory can do so in one vectored I/O operation. For example, writing a fixed-size header and its associated payload data that are placed non-sequentially in memory can be done by a single vectored I/O operation without first concatenating the header and the payload to another buffer
  • Efficiency: one vectored I/O read or write can replace many ordinary reads or writes, and thus save on the overhead involved in syscalls
  • Splitting input: when reading data held in a format that defines a fixed-size header, one can use a vector of buffers in which the first buffer is the size of that header; and the second buffer will contain the data associated with the header

Standards bodies document the applicable functions readv[http://www.opengroup.org/onlinepubs/009695399/functions/readv.html readv] {{Webarchive|url=https://web.archive.org/web/20080905083604/http://www.opengroup.org/onlinepubs/009695399/functions/readv.html |date=2008-09-05 }} in the Single Unix Specification and writev[http://www.opengroup.org/onlinepubs/009695399/functions/writev.html writev] {{Webarchive|url=https://web.archive.org/web/20071217075647/http://www.opengroup.org/onlinepubs/009695399/functions/writev.html |date=2007-12-17 }} in the Single Unix Specification 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.[http://msdn2.microsoft.com/en-us/library/aa365469.aspx ReadFileScatter] in MSDN Library 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[http://www.and.org/vstr/ Vstr] {{Webarchive|url=https://web.archive.org/web/20170305020810/http://www.and.org/vstr/ |date=2017-03-05 }} the Vectored String API

for working efficiently can mitigate the difficulties.

Examples

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.

  1. include
  2. include
  3. include
  1. include
  2. include

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 =

Rust provides the {{Code|write_vectored}} method on the {{Code|Write}} trait.{{cite web |title=Write in std::io - Rust |url=https://doc.rust-lang.org/std/io/trait.Write.html#method.write_vectored |website=doc.rust-lang.org |access-date=26 January 2025}}

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(())

}

See also

References