首页 > 解决方案 > FileChannel.transferTo(据说是零拷贝)没有带来任何性能提升

问题描述

我正在开发一个 REST API,它有一个端点来下载一个大小可能 > 2 GB 的文件。我已经读过,FileChannel.transferTo(...)如果操作系统支持,Java 将使用零拷贝。在我的 MacBook Pro OS 10.11.6 上开发期间,我的服务器在 localhost 上运行。

我比较了以下两种将文件写入响应流的方法:

  1. 将固定数量的字节从复制FileChannelWritableByteChannel使用transferTo
  2. 从字节数组(大小为 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/

标签: sendfilezero-copy

解决方案


您引用的(高)传输速率可能接近或处于 SATA 设备可以做的极限。如果我的猜测是正确的,您将不会看到运行测试所需的时间反映出性能提升 - 但是在测试期间 CPU 负载可能会发生变化。鉴于你有一台相对强大的机器,你的 CPU 和内存足够快。任何方法(无论是否零复制)都将以相同的速度工作 - 这就是您的磁盘速度。但是,零拷贝会减少 CPU 负载,也不会从内存中获取不必要的带宽。因此,您应该测试不同的方法,看看哪一种最终使用最少的 CPU,然后为您的应用程序选择该方法。


推荐阅读