Spring Reactor Webflux 调度程序并行性

use*_*934 5 spring project-reactor reactor-netty spring-webflux spring-reactor

对于完全非阻塞的端到端反应式调用,是否建议显式调用publishOn或subscribeOn来切换调度程序?对于 cpu 消耗或非消耗任务,始终使用并行通量来优化性能是否有利?

Ani*_*wat 3

对于完全非阻塞的端到端反应式调用,是否建议显式调用publishOn或subscribeOn来切换调度程序?

publishOn当您向下游发布数据时使用,而subscribeOn当您从上游消费数据时使用。所以这实际上取决于您想要执行什么样的工作。

对于 cpu 消耗或非消耗任务,始终使用并行通量来优化性能是否有利?

绝对不是,考虑这个例子:

Flux.range(1, 10)
        .parallel(4)
        .runOn(Schedulers.parallel())
        .sequential()
        .elapsed()
        .subscribe(i -> System.out.printf(" %s ", i));
Run Code Online (Sandbox Code Playgroud)

上面的代码完全是浪费,因为i几乎会立即处理。下面的代码将比上面的执行得更好:

Flux.range(1, 10)
        .elapsed()
        .subscribe(i -> System.out.printf(" %s ", i));
Run Code Online (Sandbox Code Playgroud)

现在考虑一下:

public static <T> T someMethodThatBlocks(T i, int ms) {
    try { Thread.sleep( ms ); }
    catch (InterruptedException e) {}
    return i;
}

// some method here
Flux.range(1, 10)
        .parallel(4)
        .runOn(Schedulers.parallel())
        .map(i -> someMethodThatBlocks(i, 200))
        .sequential()
        .elapsed()
        .subscribe(i -> System.out.printf(" %s ", i));
Run Code Online (Sandbox Code Playgroud)

输出类似于:

 [210,3]  [5,1]  [0,2]  [0,4]  [196,6]  [0,8]  [0,5]  [4,7]  [196,10]  [0,9] 
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,第一个响应在毫秒之后出现210,随后是 3 个响应,0其间的时间间隔很近。这个循环一次又一次地重复。这是您应该使用并行通量的地方。请注意,创建更多数量的线程并不能保证性能,因为当线程数量更多时,上下文切换会增加大量开销,因此应该在部署之前对代码进行测试。如果存在大量阻塞调用,则每个 cpu 拥有超过 1 个线程可能会提高性能,但如果进行的调用是 cpu 密集型,则每个 cpu 拥有超过 1 个线程会因上下文切换而降低性能。

所以总而言之,这始终取决于您想要实现的目标。