sendfile - FileChannel.transferTo(据说是零拷贝)没有带来任何性能提升
问题描述
我正在开发一个 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/
解决方案
您引用的(高)传输速率可能接近或处于 SATA 设备可以做的极限。如果我的猜测是正确的,您将不会看到运行测试所需的时间反映出性能提升 - 但是在测试期间 CPU 负载可能会发生变化。鉴于你有一台相对强大的机器,你的 CPU 和内存足够快。任何方法(无论是否零复制)都将以相同的速度工作 - 这就是您的磁盘速度。但是,零拷贝会减少 CPU 负载,也不会从内存中获取不必要的带宽。因此,您应该测试不同的方法,看看哪一种最终使用最少的 CPU,然后为您的应用程序选择该方法。
推荐阅读
- automation - Appium - 在 PageFactory 获取 java.lang.RuntimeException: java.lang.NoSuchMethodException: jdk.proxy2.$Proxy9.proxyClassLookup()
- node.js - 在 Mongodb 中执行查找操作后如何发送分页结果作为响应?
- javascript - 访问上传的文件 react 文件输入 onChange
- dfa - DFA 可以有一个带有空字符串的箭头作为输入吗?
- c++ - 函数是否在返回值后立即终止,忽略其下一行?
- flutter - Flutter IconTheme 不适用
- windows - 聪明的。卡微型驱动程序测试库加载失败 - cmck
- jenkins - 如何简单地执行键的值,其中值是元素列表,每个元素执行应该在jenkins groovy中并行执行
- reactjs - (错误)AWS 作为后端安装放大库
- discord - 链接到 Discord.py Meme 命令中的 meme