跳到主要内容

用 ParallelFlux 并行处理任务

Doubao 中英对照 Parallelizing Work with ParallelFlux Parallelizing Work with ParallelFlux

如今多核架构已是寻常之物,能够轻松地并行处理任务就显得尤为重要。Reactor 为此提供了一种特殊类型 ParallelFlux,它暴露了为并行处理优化过的操作符。

要得到一个 ParallelFlux,您可以在任意 Flux 上使用 parallel() 操作符。这个方法本身并不会并行执行任务,而是把工作负载划分成若干“轨道(rail)”(默认情况下,轨道数与 CPU 核心数相同)。

为了告诉得到的 ParallelFlux 每条轨道在哪里运行(从而让各轨道并行运行),您必须使用 runOn(Scheduler)。请注意,并行工作有一个推荐的专用 Scheduler:Schedulers.parallel()。

请对比下面两个示例:

Flux.range(1, 10)
.parallel(2) 1
.subscribe(i -> System.out.println(Thread.currentThread().getName() + " -> " + i));
  • 我们强制指定轨道数量,而不依赖 CPU 核心数。

Flux.range(1, 10)
.parallel(2)
.runOn(Schedulers.parallel())
.subscribe(i -> System.out.println(Thread.currentThread().getName() + " -> " + i));

第一个示例产生如下输出:

main -> 1
main -> 2
main -> 3
main -> 4
main -> 5
main -> 6
main -> 7
main -> 8
main -> 9
main -> 10

第二个示例则正确地在两个线程上并行执行,输出如下:

parallel-1 -> 1
parallel-2 -> 2
parallel-1 -> 3
parallel-2 -> 4
parallel-1 -> 5
parallel-2 -> 6
parallel-1 -> 7
parallel-1 -> 9
parallel-2 -> 8
parallel-2 -> 10

如果在并行处理完序列之后,您想回到一个“普通”的 Flux,并以顺序方式应用操作符链的其余部分,可以使用 ParallelFlux 上的 sequential() 方法。

请注意,如果您用一个 Subscriber 去 subscribe 这个 ParallelFlux,sequential() 会被隐式应用;但使用基于 lambda 的 subscribe 变体时则不会。

还要注意,subscribe(Subscriber<T>) 会把所有轨道合并起来,而 subscribe(Consumer<T>) 则会运行所有轨道。如果 subscribe() 方法传入的是 lambda,那么该 lambda 会按轨道数量被执行相应次数。

您还可以通过 groups() 方法访问各条独立轨道(或称“分组”),它们以 Flux<GroupedFlux<T>> 的形式呈现,并可通过 composeGroup() 方法对其应用额外的操作符。