Vectored I/O

Revision as of 17:36, 14 March 2025 by imported>Edgar.bonet (Undid revision 1280321197 by 129.97.124.237 (talk): writev() is a C API: a C example is more relevant than a C++ example.)
(diff) ← Previous revision | Latest revision (diff) | Newer revision → (diff)

Template:Short description Template:About

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<ref>readv Template:Webarchive in the Single Unix Specification</ref> and writev<ref>writev Template:Webarchive in the Single Unix Specification</ref> 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.<ref>ReadFileScatter in MSDN Library</ref> 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<ref>Vstr Template:Webarchive the Vectored String API</ref> for working efficiently can mitigate the difficulties.

ExamplesEdit

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.

<syntaxhighlight lang="c">

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>
  1. include <unistd.h>
  2. 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; } </syntaxhighlight>

RustEdit

Rust provides the <syntaxhighlight lang="text" class="" style="" inline="1">write_vectored</syntaxhighlight> method on the <syntaxhighlight lang="text" class="" style="" inline="1">Write</syntaxhighlight> trait.<ref>{{#invoke:citation/CS1|citation |CitationClass=web }}</ref> <syntaxhighlight lang="rust"> 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(())

} </syntaxhighlight>

See alsoEdit

ReferencesEdit

Template:Reflist