零拷贝主要关注两个核心点:线程上下文切换次数、数据在内存中被拷贝的次数;
因为线程上下文切换和在内存中拷贝数据,这两种操作都很耗CPU时间,所以要提升效率,就要尽量减少这两种操作。
一、原始阶段(上图左):
最符合直觉的方式。
整个过程公发生:2次内存数据拷贝,4次线程上下文切换。
二、MMAP + write阶段(上图右):
在用户态和内核态间开辟了一块共享内存,从磁盘传输到内核态的数据就放在这块共享缓冲区上,用户缓冲区也可以共享地访问,省去了内核缓冲区到用户缓冲区的拷贝过程。
最后用户线程再发起内核调用write,将共享缓冲区的数据拷贝到socket缓冲区,供网卡读取。
整个过程公发生:1次内存数据拷贝,4次线程上下文切换。
三、sendfile阶段(上图左):
用户线程发起sendfile系统调用,此过程将内存缓冲区到用户缓冲区的拷贝过程剔除;
直接将数据从内核缓冲区拷贝到socket缓冲区,然后线程再切回到用户态。
整个过程公发生:1次内存数据拷贝,2次线程上下文切换。
四、sendfile + DMA收集阶段(上图右):
与上一阶段类似,用户线程发起sendfile系统调用,此过程也将内存缓冲区到用户缓冲区的拷贝过程剔除;
但不直接将数据从内核缓冲区拷贝到socket缓冲区,而是将数据在内核缓冲区中的地址和数据长度拷贝到socket缓冲区;
网卡读到socket缓冲区中的地址,发现数据不在socket缓冲区中,就让DMA直接去内存缓冲区中读数据。
最后线程再切回到用户态。
整个过程公发生:0次内存数据拷贝,2次线程上下文切换。