sendfile
从那以后一直存在,并且仍然是零拷贝(假设硬件允许,但通常是这样)。零拷贝是首先拥有这个系统调用的全部意义。sendfile
现在被实现为splice
.
这表明splice
也是零拷贝,而且确实如此。至少在理论上,至少在某些情况下是这样。问题在于弄清楚如何正确使用它,以便它可靠地工作,因此它是零拷贝。至少可以说,文档是……稀疏的。
特别是,splice
如果页面是作为“礼物”提供的,即您不再拥有它们(正式,但实际上您仍然拥有),则仅适用于零拷贝。如果您只是将文件描述符拼接到套接字上,这不是问题,但如果您想将数据从应用程序的地址空间或从一个管道拼接到另一个管道,这将是一个大问题。目前还不清楚之后(以及何时)如何处理这些页面。该文档指出,您以后不得触摸这些页面或对它们做任何事情,永远不会,永远不会。因此,如果您按照文档的字母进行操作,则必须泄漏内存。
这显然是不正确的(不可能),但没有好的方法知道(至少对您而言!)何时可以安全地重用或释放该内存。内核做一个sendfile
会知道,因为一旦它收到 TCP ACK,它就知道不再需要该数据。问题是,您永远看不到 ACK。您只知道何时splice
返回的是数据已被接受发送(但您不知道它是否已经发送或接收,也不知道何时会发生)。
这意味着您需要在应用层以某种方式解决这个问题,或者通过手动 ACK(通过可靠的 UDP 免费提供),或者假设如果对方发送了对您的请求的回答,他们显然一定已经收到了请求.
您必须管理的另一件事是有限的管道空间。默认是很小的,但即使你增加大小,也不能天真地拼接任意大小的文件。sendfile
另一方面,只会让你这样做,这很酷。
总而言之,sendfile
很好,因为它可以工作,而且效果很好,而且您不需要关心上述任何细节。它不是灵丹妙药,但它确实是一个很好的补充。
就个人而言,我会远离splice
它的家人,直到整个事情得到彻底检修,直到 100% 清楚你必须做什么(以及何时)以及你不必做什么。
write
无论如何,对于大多数应用程序而言,与普通旧设备相比,真正有效的收益是微不足道的。我记得几年前 Torvalds 先生的一些不太礼貌的评论(当时 BSD 有一种形式write
可以通过重新映射页面来获得零拷贝,而 Linux 没有)它指出制作副本通常不是任何问题,但是玩页面技巧是[不会在此处重复]。