非同步與高效能輸入輸出

向量式/散聚 I/O(scatter-gather;readv/writev)

/ readv -> read-VEE; writev -> write-VEE; iovec -> EYE-oh-vek /

假設你要寄一封信,它的開頭、正文與結尾分別在你桌上三個不同的資料夾裡,而你不想為了寄出而先把三者影印到同一張紙上。更好的是指著這三個資料夾說「把這些,照這個順序,當成一封信寄出」。向量式 I/O 對位元組做的正是這件事:一個系統呼叫把「好幾個」分開的記憶體緩衝區當成一條連續的串流來讀入或寫出。

其機制是一個 iovec 的陣列。一個 struct iovec 就是一對:一個指標 iov_base 與一個長度 iov_len,指名一塊記憶體。你建好這些區塊的陣列,傳給 writev(fd, iov, count),它把這些區塊聚攏起來、依序當成單一操作寫出;readv(fd, iov, count) 則相反,把進來的位元組散開、一塊接一塊地填滿。例如要送出一則 HTTP 回應,你可以把狀態列放在一個緩衝區、標頭放在另一個、本體放在第三個,然後一次 writev() 全部三者——不必先手動串接進一個暫時緩衝區。「散」(readv)與「聚」(writev)這兩個名字描述的是「把位元組散到許多緩衝區」對「從許多緩衝區收集位元組」。

為何重要:向量式 I/O 移除了一整類不必要的複製,讓你能把標頭、框架與酬載保留在它們天生分開的緩衝區裡,卻仍只發出「一個」系統呼叫——更少的系統呼叫與更少的複製,在大規模下兩者都珍貴。它是高效協定編碼器背後的基本構件,並與零複製、與 io_uring(它直接吃 iovec)天生相配。同樣的 iovec 陣列也出現在 sendmsg()/recvmsg() 裡,並且是整個 Unix I/O 介面中表達散聚的方式。

struct iovec iov[2]; iov[0].iov_base = header; iov[0].iov_len = hlen; iov[1].iov_base = body; iov[1].iov_len = blen; ssize_t n = writev(fd, iov, 2); /* 先標頭後本體,一個系統呼叫 */

writev() 聚攏兩個分開的緩衝區、當成一次連續寫入送出——不需暫時的串接緩衝區。

writev() 仍可能寫出比要求更少的位元組(短寫),所以在大規模下你必須追蹤跨 iovec 陣列已寫到哪裡、並重新提交剩餘部分——短寫的現實不會只因你用了向量式 I/O 就消失。

又称
scatter-gather I/Oiovec-based I/O散聚 I/O(scatter-gather)