如何获得Files.walk的并行流?

Dav*_*ica 8 java lambda file java-8 java-stream

我需要递归地对文件夹中的所有文件进行一些只读处理.我正在使用Files.walk获取文件流,但我注意到api指定walk只返回常规流,而不是并行流.

如何并行处理目录中的所有文件?

Flo*_*own 17

您可以通过调用将任何变换Stream为并行.StreamStream::parallel

Stream<Path> stream = Files.walk(startPath).parallel().forEach(...);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`Files.walk`并行化很差,特别是如果您的子树少于1024个文件.如果你有很多的文件处理而不是那么多的文件,那么`Files.walk(path).collect(toList()).parallelStream()`可能会更有效. (13认同)
  • @DavidGrinberg,JDK源代码和基准测试.它在内部使用`Spliterators.spliteratorUnknownSize`,拆分策略是将块加载到以1024个元素开头的数组中.由于大小未知,Stream管道引擎假定split生成偶数部分,但它们实际上不是(首先分割为<= 1024输入,将所有元素转储为前缀,不留下后缀的元素).这导致非常糟糕的并行性能. (8认同)

小智 5

我遇到过同样的问题。Files.walk 流似乎不能并行工作。通过调用parallel()处理将流转换为并行流之后,只在一个线程中执行。

Paths正如 Tagir Valeev 所提到的,唯一的解决方案是将收集到的列表转换为列表并在此列表上创建一个并行流。

不工作的解决方案:

Files.walk(Paths.get(System.getProperty("user.dir")))
                    .parallel()
                    .filter(Files::isRegularFile)
                    ...
Run Code Online (Sandbox Code Playgroud)

工作解决方案:

Files.walk(Paths.get(System.getProperty("user.dir")))
                    .collect(Collectors.toList())
                    .parallelStream()
                    .filter(Files::isRegularFile)
                    ...
Run Code Online (Sandbox Code Playgroud)