如何施加反压来限制Publisher
产生的项目比并行运行的flatMap
可以处理的更多?
出于说明目的,有一个快速的Twitter用户名生成器,一个缓慢的Twitter查找调用,一个缓慢的Twitter文件编写器和一种打印方法。
private Consumer<FluxSink<String>> twitterUsernameGenerator() {
return (sink) -> Stream.of("a", "b", "c", "d").forEach(sink::next);
}
private Flux<TwitterMessage>findTwitterMessagesByUsername() {
return Flux.create(sink -> {
sink.next(new TwitterMessage(...));
sleep(2000);
sink.next(new TwitterMessage(...));
}
});
}
private void print(Object o) {
System.out.println("[" + Thread.currentThread().getName() + "] " + o);
}
最终目标是在对生成器施加反压的同时并行运行Twitter查找,以使用户名不会超出可处理的范围(预计会进行一些预取)。
Flux.create(twitterUsernameGenerator())
.publishOn(Schedulers.single())
.doOnNext(this::print)
.subscribe();
这可以在一个单独的线程上很好地产生5个Twitter用户名
[single-1] a
[single-1] b
[single-1] c
[single-1] d
不确定它是否正确,但我认为flatMap
从一个用户名生成许多Twitter消息,而parallel
在两个线程上执行此 I / O密集操作。
Flux.create(twitterUsernameGenerator())
.publishOn(Schedulers.single())
.doOnNext(this::print)
.parallel(2)
.runOn(Schedulers.newParallel("p", 2))
.flatMap(username -> findTwitterMessagesByUsername(username))
.doOnNext(this::print)
.subscribe();
哇!生成器生成用户名的速度比我们处理的速度更快。
[single-1] a
[single-1] b
[single-1] c
[single-1] d
[p-1] TwitterMessage{...}
[p-2] TwitterMessage{...}
...
如何对发生器功能施加反压,以使结果更接近于此
[single-1] a
[single-1] b
[p-1] TwitterMessage{...}
[single-1] c
[p-2] TwitterMessage{...}
[single-1] d
...
答案 0 :(得分:0)
背压发生在大于4个元素的“批次”中。如果您修改生成器以生成更多用户名,例如
private Consumer<FluxSink<String>> twitterUsernameGenerator() {
return (sink) -> IntStream.rangeClosed(0, 100000)
.boxed().map(String::valueOf)
.collect(Collectors.toList())
.forEach(sink::next);
}
产生的通量的行为与预期的相似。
您可以在原始Flux中添加onBackpressureError()
:
Flux.create(twitterUsernameGenerator())
.onBackpressureError()
.publishOn(Schedulers.single())
.....
通过抛出异常可以清楚地表明何时发生背压。