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