我希望对出现的项目进行批处理,所以我创建了一个UnicastProcessor并像这样订阅了它
UnicastProcessor<String> processor = UnicastProcessor.create()
processor
.bufferTimeout(10, Duration.ofMillis(500))
.subscribe(new Subscriber<List<String>>() {
@Override
public void onSubscribe(Subscription subscription) {
System.out.println("OnSubscribe");
}
@Override
public void onNext(List<String> strings) {
System.out.println("OnNext");
}
@Override
public void onError(Throwable throwable) {
System.out.println("OnError");
}
@Override
public void onComplete() {
System.out.println("OnComplete");
}
});
然后出于测试目的,我创建了一个新线程并开始循环添加项
new Thread(() -> {
int limit = 100
i = 0
while(i < limit) {
++i
processor.sink().next("Hello $i")
}
System.out.println("Published all")
}).start()
运行此命令后(让主线程休眠5秒钟),我可以看到所有项目都已发布,但是订阅者未触发任何事件,因此我无法处理任何已发布项目。
我在这里做什么错了?
答案 0 :(得分:0)
发布者向订阅者发送的onNext总数 必须小于或等于请求的元素总数 始终由该订阅者的订阅。 [Rule 1.1]
在您的示例中,您仅提供了一个不做任何事情的订阅者。反过来,Reactive Streams规范直接说如果您没有调用Subscription#request
方法
订户必须通过Subscription.request(long n)信号要求 接收onNext信号。 [Rule 2.1]
因此,要解决您的问题,一种可能的解决方案是按以下方式更改代码:
UnicastProcessor<String> processor = UnicastProcessor.create()
processor
.bufferTimeout(10, Duration.ofMillis(500))
.subscribe(new Subscriber<List<String>>() {
@Override
public void onSubscribe(Subscription subscription) {
System.out.println("OnSubscribe");
subscription.request(Long.MAX_VALUE);
}
@Override
public void onNext(List<String> strings) {
System.out.println("OnNext");
}
@Override
public void onError(Throwable throwable) {
System.out.println("OnError");
}
@Override
public void onComplete() {
System.out.println("OnComplete");
}
});
请注意,在此示例中,大小为Long.MAX_VALUE
的需求意味着无限制的需求,因此所有消息都将被直接推送到给定的Subscriber
[Rule 3.17]
一方面,您的示例将在提到的修复程序中正常工作。但是,另一方面,FluxProcessor#sink()
的每次调用(是接收器是FluxProcessor
的方法)将导致UnicastProcessor
的{{1}}方法的冗余调用,这在后台导致一些原子读写,如果一次创建onSubscribe
并安全地根据需要使用它的驯服次数,则可以避免这些原子读写。例如:
FluxSink
请注意,在此示例中,我执行了一个附加方法UnicastProcessor<String> processor = UnicastProcessor.create()
FluxSink<String> sink = processor.serialize().sink();
...
new Thread(() -> {
int limit = 100
i = 0
while(i < limit) {
++i
sink.next("Hello $i")
}
System.out.println("Published all")
}).start()
,该方法提供线程安全接收器,并确保同时调用serialize
不会导致违反ReactiveStreams规范。