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

时间:2016-01-13 14:44:10

标签: java performance copy nio jmh

我是Java程序员的初学者 今天,我练习了如何在java中复制文件,并尝试按照本教程 http://www.journaldev.com/861/4-ways-to-copy-file-in-java
完成本教程后,我运行了JMH Benchmark以检查性能,并使用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

这是我用过的代码

    @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();
        }
}

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

有人问,所以我试过了另一个文件。结果是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

使用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

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

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

2 个答案:

答案 0 :(得分:11)

  

TL; DR - 这是缓存问题

在任务管理器中运行基准测试打开 Performance 选项卡时,您将看到差异的来源。

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

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

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

答案 1 :(得分:1)

我在阅读@ apangin的解释后在Windows中运行资源监视器,并且跟随img是帮助我理解的结果。谢谢大家。
enter image description here