【问题标题】:FileChannel.transferTo (supposedly zero-copy) not giving any performance gainFileChannel.transferTo(据说是零拷贝)没有带来任何性能提升
【发布时间】:2018-11-21 02:48:05
【问题描述】:

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

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

  1. 使用transferTo将固定数量的字节从FileChannel复制到WritableByteChannel
  2. FileInputStream 读取固定数量的字节到一个字节数组(大小为4096)并循环写入OutputStream

使用这两种方法处理 5.2GB 文件所需的时间在 20 到 23 秒之间。我尝试了transferTo,将单次传输中的固定字节数设置为以下值:4KB(即 4 * 1024)、1MB 和 50MB。 3 种情况下的写作时间都在同一范围内。

所用时间是从进入 while 循环之前到退出 while 循环之后测量的,其中从文件中读取字节。这一切都在服务器端。网络跳跃时间不计算在内。

关于原因可能是什么的任何想法?我很确定 MacOS 10.11.6 应该支持零拷贝(即sendfile 系统调用)。

编辑 (2018 年 6 月 18 日)

我发现以下 2015 年的博客文章,说 MacOS X 上的 sendfile 已损坏。难道这个问题还存在?

https://blog.phusion.nl/2015/06/04/the-brokenness-of-the-sendfile-system-call/

【问题讨论】:

  • 在 OS 上找到的非常有趣的文章。我认为原因隐藏在这个 git repos 中,github.com/ecdavis/pants/issues/43
  • 感谢 Github 问题链接。那是从 2013 年开始的,比我的问题编辑(2015 年)中的博客文章链接早。所以我仍然不知道在 MacOS X 上 sendfile 是否仍然损坏。我想我会在 Mac 论坛(Apple 官方或其他一些好的论坛)中询问
  • FileChannel.transferTo 仅在传输套接字时使用 sendfile,如在 SocketChannel 中。
  • @AlanBateman - 来自FileChannel javadoc docs.oracle.com/javase/8/docs/api/java/nio/channels/…此方法可能比从该通道读取并写入目标通道的简单循环更有效。许多操作系统可以直接将字节从文件系统缓存传输到目标通道,而无需实际复制它们。
  • @AlanBateman - 抱歉,我想我没有仔细阅读您的评论。我以为你说只有写到SocketChannel 才使用sendfile。但是,我不明白您所说的 "transferring a socket" 是什么意思。

标签: sendfile zero-copy


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多