1.测试方式
不同大小的文件分别用普通复制方式和零拷贝方式从D盘复制到E盘,查看耗时
2.测试代码
代码如下
package lambda;
import java.io.*;
import java.nio.channels.FileChannel;
public class MainClass {
public static void main(String[] args) throws IOException {
testNormal();//普通方式复制
testZeroCopy();//零拷贝方式复制
}
private static void testNormal() throws IOException {
Long startTime = System.currentTimeMillis();
InputStream inputStream = new FileInputStream("D:\\testc.rar");
OutputStream outputStream = new FileOutputStream("E:\\testc.rar");
byte[] buffer = new byte[4096];
while (inputStream.read(buffer)>=0){
outputStream.write(buffer);
}
outputStream.flush();
Long endTime = System.currentTimeMillis();
long time = endTime-startTime;
System.out.println("执行耗时:"+time +"ms");
}
private static void testZeroCopy() throws IOException {
Long StartTime = System.currentTimeMillis();
File srcFile = new File("D:\\testc.rar");
File descFile = new File("E:\\testc2.rar");
FileChannel srcFileChannel = new RandomAccessFile(srcFile,"r").getChannel();
FileChannel descFileChannel = new RandomAccessFile(descFile,"rw").getChannel();
srcFileChannel.transferTo(0,srcFile.length(),descFileChannel);
Long endTime = System.currentTimeMillis();
Long time = endTime-StartTime;
System.out.println("零拷贝执行时间:"+time+"ms");
}
}
3.测试结果
文件大小 | 普通复制耗时(ms) | 零拷贝耗时(ms) | 普通/零拷贝 |
---|---|---|---|
1.02G | 1629 | 776 | 2.10 |
1607 | 772 | 2.8 | |
1588 | 753 | 2.11 | |
320M | 496 | 222 | 2.23 |
506 | 244 | 2.26 | |
509 | 214 | 2.38 | |
82K | 1 | 4 | 0.25 |
1 | 4 | 0.25 | |
1 | 4 | 0.25 |
由此得出结论:文件太小的时候使用零拷贝效率并不会提高,到一定大小的时候才会提高。
为什么小文件使用零拷贝效率反而会降低?
使用零拷贝会引入额外的系统调用和上下文切换开销,这些开销可能会超过直接复制的成本。
但对于大文件,复制的开销远大于系统调用和上下文切换带来的开销,所以会有提升。
4.适用场景
1)数据量大。使用零拷贝可以避免CPU的额外负担,提升数据传输效率,例如在文件传输,网络流量,视频流等应用中。
2)CPU负担重。零拷贝可以帮助释放CPU资源,因为避免了在内存和缓存之间的复制。
3)IO密集型任务。
5.java技术栈中的使用
kafka:数据持久化和网络传输的时候,使用了零拷贝技术。
netty:提供了零拷贝功能,例如在文件发送时可以使用FileRegion接口。
javaNIO:文中使用的案例。