我正在编写一个处理图像(大数据)的应用程序服务器。在将图像数据发送回客户端时,我试图最小化副本。我需要发送给客户端的已处理图像位于从 jemalloc 获得的缓冲区中。我想到将数据发送回客户端的方法是:
1)简单的写调用。
// Allocate buffer buf.
// Store image data in this buffer.
write(socket, buf, len);
2)我通过mmap而不是jemalloc获取缓冲区,尽管我认为jemalloc已经使用mmap创建了缓冲区。然后我打了一个简单的电话来写。
buf = mmap(file, len); // Imagine proper options.
// Store image data in this buffer.
write(socket, buf, len);
3)我像以前一样通过mmap获得一个缓冲区。然后我使用 sendfile 发送数据:
buf = mmap(in_fd, len); // Imagine proper options.
// Store image data in this buffer.
int rc;
rc = sendfile(out_fd, file, &offset, count);
// Deal with rc.
看起来(1)和(2)可能会做同样的事情,因为 jemalloc 可能首先通过 mmap 分配内存。不过,我不确定(3)。这真的会带来任何好处吗?本文关于 Linux 零复制方法的图 4表明,可以使用 sendfile 防止进一步的复制:
没有数据被复制到套接字缓冲区中。相反,只有带有数据位置和长度信息的描述符被附加到套接字缓冲区。DMA 引擎将数据直接从内核缓冲区传递到协议引擎,从而消除了剩余的最终副本。
如果一切顺利,这似乎是一场胜利。我不知道我的映射缓冲区是否算作内核缓冲区。我也不知道什么时候可以安全地重新使用这个缓冲区。由于 fd 和 length 是唯一附加到套接字缓冲区的内容,因此我假设内核实际上将此数据异步写入套接字。如果确实如此, sendfile 的返回意味着什么?我怎么知道什么时候重新使用这个缓冲区?
所以我的问题是:
- 将大缓冲区(在我的情况下为图像)写入套接字的最快方法是什么?图像保存在内存中。
- 在映射文件上调用 sendfile 是个好主意吗?如果是,有什么问题?这甚至会导致任何胜利吗?