Schedulers.boundedElastic 似乎使用相同的线程进行处理

时间:2021-03-17 12:39:44

标签: multithreading spring-webflux project-reactor

通过查看 API,我的理解是使用 Schedulers.boundedElastic() 或类似 Schedulers.newBoundedElastic(3, 10, "MyThreadGroup"); 的变体;或 Schedulers.fromExecutor(executor) 允许在多个线程中处理 IO 操作。

但是使用以下示例代码进行的模拟似乎表明单个线程/同一线程正在执行 flatMap 中的工作

Flux.range(0, 100)
                .flatMap(i -> {
                    try {
                        // IO operation
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("Mapping for " + i + " is done by thread " + Thread.currentThread().getName());
                    return Flux.just(i);
                })
                .subscribeOn(Schedulers.boundedElastic())
                .subscribe();

Thread.sleep(10000); // main thread

//This yields the following

Mapping for 0 is done by thread boundedElastic-1
Mapping for 1 is done by thread boundedElastic-1
Mapping for 2 is done by thread boundedElastic-1
Mapping for 3 is done by thread boundedElastic-1 ...

上面的输出向我建议在 flatMap 中运行相同的线程。当在多个 IO 的订阅上调用 flatMap 时,有没有办法让多个线程来处理项目?我期待看到 boundedElastic-1、boundedElastic-2 ... .

2 个答案:

答案 0 :(得分:0)

1.非阻塞 IO 并发(首选)

如果您有机会使用非阻塞 IO(如 Spring WebClient),那么您就无需担心线程或调度程序,并且您将获得开箱即用的并发性:

Flux.range(0, 100)
        .flatMap(i -> Mono.delay(Duration.ofMillis(500)) // e.g.: reactive webclient call
                .doOnNext(x -> System.out.println("Mapping for " + i + " is done by thread " + Thread.currentThread()
                        .getName())))
        .subscribe();

2.并发阻塞 IO

如果可以选择,最好避免阻塞 IO。如果无法避免,只需对代码稍作修改并将 subscribeOn 应用于内部 Mono

Flux.range(0, 100)
        .flatMap(i -> Mono.fromRunnable(() -> {
            try {
                // IO operation
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("Mapping for " + i + " is done by thread " + Thread.currentThread().getName());
        }).subscribeOn(Schedulers.boundedElastic()))
        .subscribe();

答案 1 :(得分:0)

让 flatMap 在多个线程上运行的一种方法是创建一个 ParallelFlux。下面的示例代码可以解决问题。

Flux.range(0, 1000)
                .parallel()             
                .runOn(Schedulers.boundedElastic())
                .flatMap(i -> {
                    try {
                        // IO operation
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("second Mapping for " + i + " is done by thread " + Thread.currentThread().getName());
                    return Flux.just(i);
                })
                .subscribe();
        
        Thread.sleep(10000);