在前面我們知道,read() 系統(tǒng)調(diào)用的過程中會把內(nèi)核緩沖區(qū)的數(shù)據(jù)拷貝到用戶的緩沖區(qū)里,于是為了減少這一步開銷,我們可以用 mmap() 替換 read() 系統(tǒng)調(diào)用函數(shù)。
mmap() 系統(tǒng)調(diào)用函數(shù)會直接把內(nèi)核緩沖區(qū)里的數(shù)據(jù)「映射」到用戶空間,這樣,操作系統(tǒng)內(nèi)核與用戶空間就不需要再進行任何的數(shù)據(jù)拷貝操作。
具體過程如下:
應(yīng)用進程調(diào)用了 mmap() 后,DMA 會把磁盤的數(shù)據(jù)拷貝到內(nèi)核的緩沖區(qū)里。接著,應(yīng)用進程跟操作系統(tǒng)內(nèi)核「共享」這個緩沖區(qū);應(yīng)用進程再調(diào)用 write(),操作系統(tǒng)直接將內(nèi)核緩沖區(qū)的數(shù)據(jù)拷貝到 socket 緩沖區(qū)中,這一切都發(fā)生在內(nèi)核態(tài),由 CPU 來搬運數(shù)據(jù);最后,把內(nèi)核的 socket 緩沖區(qū)里的數(shù)據(jù),拷貝到網(wǎng)卡的緩沖區(qū)里,這個過程是由 DMA 搬運的。
我們可以得知,通過使用 mmap() 來代替 read(), 可以減少一次數(shù)據(jù)拷貝的過程。
但這還不是最理想的零拷貝,因為仍然需要通過 CPU 把內(nèi)核緩沖區(qū)的數(shù)據(jù)拷貝到 socket 緩沖區(qū)里,而且仍然需要 4 次上下文切換,因為系統(tǒng)調(diào)用還是 2 次。