首先,如果讀者之前不熟悉什麼是零拷貝,請參考下面的連結:
Linux中的零拷貝技術,第1部分
http://www.ibm.com/developerworks/cn/linux/l-cn-zerocopy1/index.html
Linux中的零拷貝技術,第2部分
http://www.ibm.com/developerworks/cn/linux/l-cn-zerocopy2/index.html
通過零拷貝實現有效資料轉送
http://www.ibm.com/developerworks/cn/java/j-zerocopy/
連結裡給出的文章已經很好的說明了零拷貝的概念和作用(即更有效地實現資料轉送),以及如何?零拷貝。下面我們一步步地來看看普通情況下資料的發送和接收流程和使用零拷貝技術情況下資料的發送和接收流程到底有何區別,從而進一步理解零拷貝的含義及其優點。
一、資料轉送:傳統方法
考慮一下從一個磁碟檔案中讀出資料並將資料轉送到網路上另一程式的情境(這個情境表述出了很多伺服器應用程式的行為,包括提供靜態內容的 Web應用程式、FTP伺服器、郵件伺服器等)。
圖
1
資料轉送從讀磁碟檔案開始到資料到達網卡為止,整個流程說明如下:
圖
2
Step1: read()調用引發了第一次從使用者模式到核心模式的環境切換。在內部,發出
sys_read()(或等效內容)從檔案中讀取資料。DMA引擎執行了第一次拷貝/複製,它從磁碟中讀取檔案內容,然後將它們儲存到一個核心地址空間緩衝區中。
Step2:所需的資料被從讀取緩衝區拷貝到使用者緩衝區,read()調用返回。該調用的返回引發了核心模式到使用者模式的第二次環境切換。這同時產生了第二次拷貝/複製,現在資料被儲存在使用者地址空間緩衝區。
Step3: send()通訊端(或者write()調用)引發了從使用者模式到核心模式的第三次環境切換。資料被第三次拷貝/複製,並被再次放置在核心地址空間緩衝區。但是這一次放置的緩衝區不同,該緩衝區與目標通訊端相關聯。
Step4: send()調用返回,結果導致了第四次的環境切換。DMA
引擎將資料從核心緩衝區傳到協議引擎,第四次拷貝/複製獨立地、非同步地發生。
圖 3
我們可以很清楚的看到,資料在磁碟、中間核心緩衝區和使用者緩衝區中被拷貝了多次,並且經過了多次環境切換。顯然,這樣的資料轉送效率是很低下的。
而零拷貝正是通過消除這些冗餘的資料拷貝從而提高了效能,下面我們就循序漸進地看看使用零拷貝傳輸資料的情況是什麼樣的:
二、資料轉送:零拷貝方法
從文章開始的地方給出的連結中,簡要介紹了零拷貝的幾種實現方式,我們這裡針對其中的mmap實現方式進行進一步的分析。當我們仔細看傳統情況下的資料轉送,就會注意到有些拷貝操作是可以不用做的。應用程式只是起到快取資料並將其傳回到通訊端的作用而已,別無他用。我們完全可以採用所示的方式進行資料轉送:
圖
4
注意圖4與圖1的區別,圖4中使用mmap代替了圖1中的read。這會導致什麼不同呢,我們又該如何?以上的想法呢?另外,使用中間核心緩衝區,即圖2中的Read
buffer或圖4中的頁緩衝,而不是直接將資料轉送到使用者緩衝區,看起來可能有點效率低下。但是之所以引入中間核心緩衝區的目的是想提高效能。在讀取方面使用中間核心緩衝區,可以允許核心緩衝區在應用程式不需要核心緩衝區內的全部資料時,充當 “預讀快取(readahead cache)”的角色。這在所需資料量小於核心緩衝區大小時極大地提高了效能。在寫入方面的中間緩衝區則可以讓寫入過程非同步完成。不幸的是,如果所需資料量遠大於核心緩衝區大小的話,這個方法本身可能成為一個效能瓶頸。