为什么nio.files.copy比nio.fileChannel复制要慢很多?

Din*_*nwy 4 java performance nio copy jmh

我是Java初学者.
今天,我练习了如何在java中复制文件并尝试按照本教程 http://www.journaldev.com/861/4-ways-to-copy-file-in-java
完成本教程后,我运行了JMH使用57MB txt文件检查性能的基准测试.
nioFiles和NIOChannel之间存在性能差距,比我预期的要大.

Benchmark                                   Mode  Cnt   Score   Error  Units
CompressTest.fileCopyUsingNIOChannelClass  thrpt   10  22.465 ± 2.996  ops/s
CompressTest.fileCopyWithNIOFiles          thrpt   10   0.843 ± 0.488  ops/s
Run Code Online (Sandbox Code Playgroud)

这是我用过的代码

    @Warmup(iterations = 5, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
    @Measurement(iterations = 10, time = 1000, timeUnit = TimeUnit.MILLISECONDS)
    @Fork(1)
    @State(Scope.Benchmark)
    public class CompressTest
    {
    final static Path source = Paths.get("c:/temp/system.out.lambda.txt");
    final static Path target = Paths.get("c:/temp/copied.lambda.txt");

    public static void main(String[] args) throws RunnerException, IOException {
        Main.main(args);
    }

    @Benchmark
    public static void fileCopyWithNIOFiles() throws IOException{
        Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
    }
    @Benchmark
    public static void fileCopyUsingNIOChannelClass() throws IOException
        {
            File fileToCopy = new File("c:/temp/system.out.lambda.txt");
            FileInputStream inputStream = new FileInputStream(fileToCopy);
            FileChannel inChannel = inputStream.getChannel();

            File newFile = new File("c:/temp/testcopied.txt");
            FileOutputStream outputStream = new FileOutputStream(newFile);
            FileChannel outChannel = outputStream.getChannel();

            inChannel.transferTo(0, fileToCopy.length(), outChannel);
            inputStream.close();
            outputStream.close();
        }
}
Run Code Online (Sandbox Code Playgroud)

所以我想问一下,我做错了什么吗?或者你能解释为什么会这样吗?


有人问,所以我试过了另一个文件.结果是348MB avi文件及以下内容.

Benchmark                                   Mode  Cnt  Score   Error  Units
CompressTest.fileCopyUsingNIOChannelClass  thrpt   10  3.142 ± 0.738  ops/s
CompressTest.fileCopyWithNIOFiles          thrpt   10  1.991 ± 0.350  ops/s
Run Code Online (Sandbox Code Playgroud)

使用nioFile的静态文件副本比使用NIOChannel慢.


我刷新了一切,再次测试,这就是重新开始.使用57MB txt文件并将预热迭代设置为10.

Benchmark                                   Mode  Cnt   Score   Error  Units
CompressTest.fileCopyUsingNIOChannelClass  thrpt   10  23.442 ± 3.224  ops/s
CompressTest.fileCopyWithNIOFiles          thrpt   10  12.328 ± 2.128  ops/s
Run Code Online (Sandbox Code Playgroud)

这个结果比第一个结果更容易接受,但是nioFile复制的速度仍然是NIOChannel的近一半.

PS:如果有更好的方法来复制文件,请告诉我.我真的想了解更多有关java的信息,谢谢.

apa*_*gin 11

TL; DR - 这是缓存问题

在任务管理器中运行基准打开性能选项卡时,您将看到差异的来源.

Files.copy测试期间,您可能会看到高磁盘写入速度.但是当transferTo测试运行时,磁盘几乎是空闲的!这意味着实际上没有数据写入设备 - 复制在内存中执行.这显然要快得多.

Java Files.copy方法是使用CopyFileExWinAPI函数实现的.没有明确的规范如何CopyFileEx在内部工作,但是观察到它做了一些实际的磁盘I/O.

反过来transferTo做系列ReadFile/ WriteFile调用.WriteFile函数不保证数据立即写入磁盘.它可以将数据放入OS磁盘缓存中,并在后面的某个时间执行实际的设备I/O.