Linux下的零拷贝
Reference:??https://segmentfault.com/a/1190000011989008
?
零拷貝是什么?
維基百科對“零拷貝”是這樣描述的:
"Zero-copy" describes computer operations in which the CPU does not perform the task of copying data from one memory area to another. This is frequently used to save CPU cycles and memory bandwidth when transmitting a file over a network.
“零拷貝” 描述的是CPU不執(zhí)行拷貝數(shù)據(jù)從一塊內(nèi)存區(qū)域到另一塊區(qū)域的任務(wù)的計算機操作。它通常用于在網(wǎng)絡(luò)上傳輸文件時節(jié)省CPU周期和內(nèi)存帶寬。簡單來說,零拷貝就是一種避免 CPU 將數(shù)據(jù)從一塊存儲拷貝到另外一塊存儲的技術(shù)。
為什么需要零拷貝技術(shù)?
通常我們會有這樣的需求:將本地磁盤上的一個文件通過網(wǎng)絡(luò)發(fā)送給遠端的另一個服務(wù)。在傳統(tǒng)的I/O中,我們通過一張圖來看一下操作系統(tǒng)都會發(fā)生什么:
發(fā)出read()系統(tǒng)調(diào)用,這時處理器會從用戶空間切換至內(nèi)核空間;
向磁盤請求數(shù)據(jù);
通過DMA將文件從磁盤上讀取到內(nèi)核空間緩沖區(qū);
read()系統(tǒng)調(diào)用返回,將數(shù)據(jù)從內(nèi)核空間緩沖區(qū)拷貝至用戶空間緩沖區(qū),這時候處理器會從內(nèi)核空間切換至用戶空間;
發(fā)出write()系統(tǒng)調(diào)用,并將數(shù)據(jù)從用戶空間緩沖區(qū)拷貝至目標socket 在內(nèi)核空間的緩沖區(qū),這時候處理器會從用戶空間切換至內(nèi)核空間;
write()調(diào)用返回;
通過DMA將數(shù)據(jù)從內(nèi)核空間緩沖區(qū)中拷貝至協(xié)議引擎(該操作是獨立且異步的)。
總的來說:傳統(tǒng)的I/O操作在整個過程中將會產(chǎn)生4次上下文切換和4次數(shù)據(jù)拷貝。
Q:有人可能會問, 為什么write()調(diào)用會先返回,難道他會在數(shù)據(jù)傳輸前返回?
A:事實上調(diào)用的返回并不保證數(shù)據(jù)被傳輸,甚至他并不保證傳輸?shù)拈_始,只是意味著以太網(wǎng)驅(qū)動程序在其傳輸隊列中有空位,并已經(jīng)接受我們的將要傳輸?shù)臄?shù)據(jù)。在我們之前很可能還有很多數(shù)據(jù)包在排除。除非驅(qū)動程序或硬件實現(xiàn)優(yōu)先級環(huán)或隊列,否則數(shù)據(jù)都將以先進先出的方式被傳輸。
了解了傳統(tǒng)I/O的操作后,我們再來觀察一下整個過程,我們會注意到第二次和第三次數(shù)據(jù)拷貝是完全沒有意義的,應(yīng)用程序僅僅緩存了一下數(shù)據(jù)就又原封不動的把它發(fā)送給了目標socket 緩沖區(qū)。而且這兩次拷貝是需要CPU全程參與的,從操作系統(tǒng)的角度來說,如果 CPU 一直被占用著去執(zhí)行這項簡單的任務(wù),那么這將會是很浪費資源的;如果有其他比較簡單的系統(tǒng)部件可以代勞這件事情,從而使得 CPU 解脫出來可以做其他的事情,那么系統(tǒng)資源的利用則會更加有效。
“零拷貝”正是通過消除這些多余的拷貝來提升性能的。在數(shù)據(jù)傳輸?shù)倪^程中,避免數(shù)據(jù)在內(nèi)核空間緩沖區(qū)和用戶空間緩沖區(qū)之間進行拷貝,以及數(shù)據(jù)在內(nèi)核空間緩沖區(qū)內(nèi)的CPU拷貝。
零拷貝的實現(xiàn)機制
Linux 中提供類似的系統(tǒng)調(diào)用主要有 sendfile()、mmap() 和splice()(本文對該系統(tǒng)調(diào)用暫不做討論)。
通過sendfile()實現(xiàn)的零拷貝
sendfile系統(tǒng)調(diào)用在內(nèi)核版本2.1中被引入,目的是簡化通過網(wǎng)絡(luò)在兩個本地文件之間進行的數(shù)據(jù)傳輸過程。sendfile系統(tǒng)調(diào)用的引入,不僅減少了數(shù)據(jù)復制,還減少了上下文切換的次數(shù)。為了更好的說明,請看下圖:
發(fā)出sendfile()系統(tǒng)調(diào)用,這時處理器會從用戶空間切換至內(nèi)核空間;
向磁盤請求數(shù)據(jù);
通過DMA將文件從磁盤上讀取到內(nèi)核空間緩沖區(qū);
將數(shù)據(jù)從內(nèi)核空間緩沖區(qū)拷貝到目標socket緩沖區(qū);
Sendfile()返回,這時處理器從內(nèi)核空間切換至用戶空間;
通過DMA將數(shù)據(jù)從目標socket緩沖區(qū)拷貝至協(xié)議引擎。
總結(jié)一下這種實現(xiàn),整個過程產(chǎn)生了2次上下文切換和3次數(shù)據(jù)拷貝(其中2次DMA拷貝和1次CPU拷貝)。
該實現(xiàn)雖然減少了2次上下文切換,但仍然還有1次CPU拷貝。那這次拷貝是不是也可以省掉呢?答案是肯定的。但是需要底層操作系統(tǒng)的一些支持。那就是帶有DMA收集功能的sendfile實現(xiàn)的零拷貝。
帶有DMA收集功能的sendfile實現(xiàn)的零拷貝
從Linux2.4開始,操作系統(tǒng)底層提供了帶有scatter/gather的DMA來從內(nèi)核空間緩沖區(qū)中將數(shù)據(jù)讀取到協(xié)議引擎中。這就意味著等待傳輸?shù)臄?shù)據(jù)不需要在連續(xù)存儲器中,它可以分散在不同的內(nèi)存位置。那這樣一來,從文件中讀出的數(shù)據(jù)就不必拷貝至目標socket的緩沖區(qū)中,只需要將緩沖區(qū)描述符添加到目標socket的緩沖區(qū)中,DMA收集操作會根據(jù)緩沖區(qū)描述符中的信息將內(nèi)核空間緩沖區(qū)中的數(shù)據(jù)讀取到協(xié)議引擎。這種方法不僅減少了上下文切換、還減少了由CPU參與的數(shù)據(jù)拷貝。為了更好的理解這種方法所涉及的操作,請看下圖:
發(fā)出sendfile()系統(tǒng)調(diào)用,處理器從用戶空間切換至內(nèi)核空間;
通過DMA將數(shù)據(jù)copy至內(nèi)核空間緩沖區(qū);
將數(shù)據(jù)在內(nèi)核空間緩沖區(qū)的地址和偏移量拷貝至目標socket的緩沖區(qū);
Sendfile()返回,處理器從內(nèi)核空間切換至用戶空間。
帶有scatter/gather 功能的DMA將數(shù)據(jù)直接從內(nèi)核緩沖區(qū)讀取到協(xié)議引擎,從而消除了最后一次CPU拷貝。
總結(jié)一下,這種方法產(chǎn)生了2次上下文切換和2次數(shù)據(jù)拷貝。
這時有人可能會問,如果我把數(shù)據(jù)從磁盤上讀出來后,再編輯一下,再發(fā)送出去,以上所說的零拷貝豈不是不能實現(xiàn)?
對于該問題,Linux提供了mmap來實現(xiàn)。
通過mmap實現(xiàn)的零拷貝
mmap(內(nèi)存映射):mmap操作提供了一種機制,讓用戶程序直接訪問設(shè)備內(nèi)存,這種機制,相比較在用戶空間和內(nèi)核空間互相拷貝數(shù)據(jù),效率更高。
發(fā)出mmap()系統(tǒng)調(diào)用,處理器從用戶空間切換至內(nèi)核空間。
向磁盤請求數(shù)據(jù);
通過DMA將數(shù)據(jù)從磁盤拷貝至內(nèi)核空間緩沖區(qū);
mmap()調(diào)用返回,這時候用戶程序和操作系統(tǒng)共享這個緩沖區(qū),不需要再將數(shù)據(jù)從kernel buffer 拷貝至 user buffer,處理器從內(nèi)核空間切換至用戶空間;
用戶邏輯處理;
發(fā)出write()系統(tǒng)調(diào)用,將數(shù)據(jù)從內(nèi)核空間緩沖區(qū)拷貝至目標socket緩沖區(qū),這時處理器從用戶空間切換至內(nèi)核空間;
write()調(diào)用返回,處理器從內(nèi)核空間切換至用戶空間;
通過DMA將數(shù)據(jù)拷貝至協(xié)議引擎。
總結(jié)一下:這種方法將產(chǎn)生4次上下文切換和3次數(shù)據(jù)拷貝。
至此,零拷貝技術(shù)就介紹完了。本文所提及的零拷貝技術(shù)都是需要底層操作系統(tǒng)支持的,同時,零拷貝技術(shù)一直是在不斷地發(fā)展和完善當中的,本文并沒有涵蓋 Linux 上出現(xiàn)的所有零拷貝技術(shù)。
轉(zhuǎn)載于:https://www.cnblogs.com/skying555/p/11122072.html
總結(jié)
以上是生活随笔為你收集整理的Linux下的零拷贝的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Zjoi2010排列计数Perm
- 下一篇: windows下使用pip安装Pytho