我有一些传入事件流,需要对其进行充实,然后在它们到达时并行处理。
我当时以为Project Reactor是按订单生产的,但是在我的测试中,所有处理似乎都是按顺序进行的。
以下是一些测试代码:
ExecutorService executor = Executors.newFixedThreadPool(10);
System.out.println("Main thread: " + Thread.currentThread());
Flux<String> tick = Flux.interval(Duration.of(10, ChronoUnit.MILLIS))
.map(i-> {
System.out.println("ReactorTests.test " + Thread.currentThread());
sleep(1000L); // simulate IO delay
return String.format("String %d", i);
})
.take(3)
// .subscribeOn(Schedulers.elastic());
// .subscribeOn(Schedulers.newParallel("test"));
// .subscribeOn(Schedulers.fromExecutor(executor));
;
tick.subscribe(x ->System.out.println("Subscribe thread: " + Thread.currentThread()),
System.out::println,
()-> System.out.println("Done"));
System.out.println("DONE AND DONE");
我尝试取消注释的每一行的注释,但是在每种情况下,输出都表明使用同一线程来处理所有事件
Main thread: Thread[main,5,main]
[DEBUG] (main) Using Console logging
DONE AND DONE
ReactorTests.test Thread[parallel-1,5,main]
Subscribe thread: Thread[parallel-1,5,main]
ReactorTests.test Thread[parallel-1,5,main]
Subscribe thread: Thread[parallel-1,5,main]
ReactorTests.test Thread[parallel-1,5,main]
Subscribe thread: Thread[parallel-1,5,main]
Done
(唯一的区别是,没有调度程序,它们在预订线程上运行,而对于任何执行程序,它们都在同一线程上运行,而不是在订阅线程上。)
我想念什么?
仅供参考,有一种“睡眠”方法:
public static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
System.out.println("Exiting");
}
}
答案 0 :(得分:1)
并行处理项目的一种方法是使用.parallel
/ .runOn
flux
.parallel(10)
.runOn(scheduler)
//
// Work to be performed in parallel goes here. (e.g. .map, .flatMap, etc)
//
// Then, if/when you're ready to go back to sequential, call .sequential()
.sequential()
阻塞操作(例如阻塞IO或Thread.sleep
)将阻塞执行它们的线程。反应流无法神奇地将阻止方法转变为非阻止方法。因此,您需要确保在适合于阻塞操作的Scheduler
上运行阻塞方法(例如Schedulers.elastic()
)。
在上面的示例中,由于您知道要调用阻塞操作,因此可以使用.runOn(Schedulers.elastic())
。
根据使用情况,您还可以将.flatMap
之类的异步运算符与.subscribeOn
或.publishOn
结合使用,将特定的阻塞操作委托给另一个Scheduler
,例如{ {3}}。例如:
flux
.flatMap(i -> Mono.fromCallable(() -> {
System.out.println("ReactorTests.test " + Thread.currentThread());
sleep(1000L); // simulate IO delay
return String.format("String %d", i);
})
.subscribeOn(Schedulers.elastic()))
实际上,.flatMap
也有一个重载的变体,它带有一个concurrency
参数,您可以在其中限制飞行中内部序列的最大数量。在某些用例中,可以使用它代替.parallel
。不过,由于Flux.interval
不支持下游请求的补充速度比滴答声慢,因此它通常不适用于Flux.interval
。