我正在开发一个REST API,它有一个端点可以下载一个可能是>的文件。 2 GB大小。我已经读过,如果操作系统支持,那么Java FileChannel.transferTo(...)
将使用零拷贝。在我的MacBook Pro OS 10.11.6上进行开发期间,我的服务器在localhost上运行。
我将以下两种将文件写入响应流的方法进行了比较:
FileChannel
WritableByteChannel
复制到transferTo
FileInputStream
读取固定数量的字节到字节数组(大小为4096)并在循环中写入OutputStream
。使用这两种方法,5.2GB文件所需的时间在20到23秒之间。我尝试transferTo
将单个传输中的固定字节数设置为以下值:4KB(即4 * 1024),1MB和50MB。在所有3个案例中,写作所用的时间都在相同的范围内。
从进入while循环之前到退出while循环之前测量所花费的时间,其中从文件中读取字节。这一切都在服务器端。网络跳跃时间没有考虑到这一点。
关于原因可能是什么的任何想法?我确信MacOS 10.11.6应该支持零拷贝(即sendfile
系统调用)。
编辑 (6/18/2018):
我在2015年发现了以下博文,称MacOS X上的sendfile
已被破坏。难道这个问题仍然存在吗?
https://blog.phusion.nl/2015/06/04/the-brokenness-of-the-sendfile-system-call/
答案 0 :(得分:1)
您所引用的(高)传输速率很可能接近或限制SATA设备可以执行的操作。如果我的猜测是正确的,那么您将不会在运行测试的时间中看到性能的提高-但是在测试过程中,CPU负载可能会发生变化。假设您有一台相对强大的计算机,则您的CPU和内存足够快。任何方法(无论是否为零拷贝)都可以相同的速度工作-这就是磁盘的速度。但是,零拷贝将减少CPU负载,也不会从内存中获取不必要的带宽。因此,您应该测试不同的方法,然后看看哪种方法最终使用最少的CPU并为您的应用程序选择该方法。