Linux有零拷贝吗?拼接或发送文件?

Elo*_*off 25 c linux zero-copy

当引入splice时,在内核列表中讨论了sendfile是基于splice重新实现的.splice SLICE_F_MOVE的文档说明:

尝试移动页面而不是复制.这只是内核的提示:如果内核无法从管道中移动页面,或者管道缓冲区没有引用整页,则仍可能会复制页面.这个标志的初始实现是错误的:因此从Linux 2.6.21开始它是一个无操作(但仍然允许在splice()调用中); 将来,可以恢复正确的实施.

这是否意味着Linux没有写入套接字的零拷贝方法?或者这是在某些时候修复的,多年来没有人更新文档?sendfile或splice中的任何一个在任何最新的3.x内核版本中都有零拷贝实现吗?

由于谷歌没有回答这个问题,我正在为下一个可怜的骗子创建一个stackoverflow问题,他想知道使用vmsplice和splice或sendfile是否有利于普通旧写.

Dam*_*mon 16

sendfile从那时起,它仍然是零拷贝(假设硬件允许它,但通常就是这种情况).零拷贝是首先拥有这个系统调用的全部要点.sendfile现在被实现为包装器splice.

这表明,splice零拷贝也是如此,事实确实如此.至少在理论上,至少在某些情况下.问题是弄清楚如何正确使用它,以便它可靠地工作,因此它是零拷贝.至少可以说文档是......稀疏的.

特别是,splice如果页面被赋予"礼物",则只能进行零拷贝,即您不再拥有它们(正式,但实际上您仍然这样做).如果您只是将文件描述符拼接到套接字上,那么这是一个非问题,但如果您想要将数据从应用程序的地址空间或从一个管道拼接到另一个管道,则这是一个大问题.目前还不清楚如何处理页面(以及何时).文档说明您之后可能不会触摸页面或对它们执行任何操作,永远不会.因此,如果您按照文档的说明,则必须泄漏内存.
这显然是不正确的(它不可能),但是当重用或释放内存时,没有好的方法(对于你至少!).执行a的内核sendfile会知道,因为一旦收到TCP ACK,它就知道再也不需要数据了.问题是,你永远不会看到一个ACK.你知道什么时候splice返回的是数据已被接受发送(但你不知道它是否已被发送或接收,也不会发生这种情况).
这意味着你需要算出这个莫名其妙的应用层上,无论是通过做手工的ACK(自带免费使用可靠UDP),或通过假设如果对方将回答您的要求,他们显然必须得到请求.

你需要管理的另一件事是有限的管道空间.默认值非常小,但即使您增加了大小,也不能只是天真地拼接任何大小的文件.sendfile另一方面,只会让你这样做,这很酷.

总而言之,这sendfile很好,因为它只是有效,并且运行良好,您无需关心上述任何细节.它不是灵丹妙药,但肯定是一个很好的补充.
我个人会远离splice它和它的家人,直到整个事情被彻底改变,直到你100%清楚你必须做什么(什么时候)以及你不必做什么.

write无论如何,对于大多数应用来说,真实有效的收益对于大多数应用来说是微不足道 我记得由托沃兹先生有些小于礼貌评论几年前(BSD时有形式write,将做一些魔术重新映射页面以获得零拷贝,和Linux都没有),它指出,制作副本通常不是任何问题,但玩页面的技巧是[这里不再重复].

  • Torvalds的引用是指BSD人员如何将这些页面标记为写时复制.这需要TLB刷新,这是非常昂贵的,大约2000个周期,并且如果你在内核完成之前写入该缓冲区,它无论如何都会进行复制,使你正好处于负面区域. (4认同)
  • Torvalds:"我声称Mach人(显然是FreeBSD)是不称职的白痴.用VM玩游戏很糟糕.内存副本也很糟糕,但坦率地说,内存副本通常比VM游戏没有下降,更大的缓存只会继续把这一点赶回家." http://yarchive.net/comp/linux/splice.html (3认同)
  • @Ben:是的,这就是引用:-) (2认同)
  • @ Eloff,Linux表示,使用循环缓冲区两倍于内核缓冲区大小,无需进行安全检查即可完成:http://yarchive.net/comp/linux/splice.html (2认同)