我正在开发一个 REST API,它有一个端点来下载一个大小可能 > 2 GB 的文件。我已经读过,FileChannel.transferTo(...)
如果操作系统支持,Java 将使用零拷贝。在我的 MacBook Pro OS 10.11.6 上开发期间,我的服务器在 localhost 上运行。
我比较了以下两种将文件写入响应流的方法:
- 将固定数量的字节从复制
FileChannel
到WritableByteChannel
使用transferTo
- 从字节数组(大小为 4096)中读取固定数量的字节
FileInputStream
并循环写入OutputStream
。
使用这两种方法,一个 5.2GB 文件所需的时间在 20 到 23 秒之间。我尝试transferTo
将单个传输中的固定字节数设置为以下值:4KB(即 4 * 1024)、1MB 和 50MB。在所有 3 种情况下,写入时间都在相同的范围内。
所用时间是从进入 while 循环之前到退出 while 循环之后测量的,其中从文件中读取字节。这一切都在服务器端。网络跳跃时间不计算在内。
关于原因可能是什么的任何想法?我很确定 MacOS 10.11.6 应该支持零拷贝(即sendfile
系统调用)。
编辑 (2018 年 6 月 18 日):
我发现了 2015 年的以下博客文章,说sendfile
在 MacOS X 上已损坏。难道这个问题还存在?
https://blog.phusion.nl/2015/06/04/the-brokenness-of-the-sendfile-system-call/