如何确保反应堆通量处理所提供的所有消息

时间:2017-11-09 02:25:32

标签: reactive-programming project-reactor

假设我们想让Flux管道处理来自多个线程的所有消息。我们考虑下面的代码:

@Test
public void testFluxCreate() throws InterruptedException {
    EmitterProcessor<String> processor = EmitterProcessor.create();
    CountDownLatch latch = new CountDownLatch(1);

    AtomicLong counter = new AtomicLong();
    AtomicLong batch = new AtomicLong();
    Flux<List<String>> flux = processor
            .doOnSubscribe(ss -> System.out.println(nm() + " : subscribing to + ss))
            .onBackpressureError()
            .buffer(7)
            .publishOn(Schedulers.immediate())
            .doOnNext(it -> {
                counter.addAndGet(it.size());
                System.out.println(batch.incrementAndGet() + " : " + nm() + "Batch: " + it.size());
            })
            ;

    CompletableFuture<Void> producer = CompletableFuture.runAsync(() -> {
        IntStream.range(1, 1001).forEach(it -> {
            //sleep();
            processor.onNext("Message-" + it);
        });
    });

    CompletableFuture<Void> producer2 = CompletableFuture.runAsync(() -> {
        IntStream.range(1, 1001).forEach(it -> {
            //sleep();
            processor.onNext("Message2-" + it);
        });
    });

    CompletableFuture<Void> future = CompletableFuture.allOf(producer, producer2).thenAccept(it -> processor.onComplete());

    flux.doOnComplete(latch::countDown).subscribe();

    future.join();
    latch.await();

    System.out.println("Total: " + counter);
}

计数器告诉我们,每次执行此代码时,处理的实际消息数都是不同的。 这个实现有什么问题? 我们如何确保在程序结束之前处理所有消息?

1 个答案:

答案 0 :(得分:1)

  

这个实现有什么问题?

当我运行代码时,我在开始后的日志中得到以下内容:

BooleanView.xib

我不熟悉class BooleanView: UIView { @IBOutlet var contentView: UIView! @IBOutlet weak var leftButton: UIButton! @IBOutlet weak var rightButton: UIButton! //MARK: Initialization override init(frame: CGRect) { super.init(frame: frame) // Load the nib named 'CardView' into memory, finding it in the main bundle. Bundle.main.loadNibNamed("BooleanView", owner: self, options: nil) self.frame = contentView.frame addSubview(contentView) // Style the custom view contentView.backgroundColor = UIColor.clear leftButton.layer.cornerRadius = (leftButton.frame.height / 2) rightButton.layer.cornerRadius = (rightButton.frame.height / 2) } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder)! } @IBAction func pressedButton(_ sender: UIButton) { if sender.backgroundColor == Constants.BOOL_BUTTON.enabled { return } sender.backgroundColor = Constants.BOOL_BUTTON.enabled sender.titleLabel?.font = UIFont(name: Constants.FONTS.bold, size: (sender.titleLabel?.font.pointSize)!) if sender.tag == 0 { self.rightButton.backgroundColor = Constants.BOOL_BUTTON.disabled self.rightButton.titleLabel?.font = UIFont(name: Constants.FONTS.regular, size: (self.rightButton.titleLabel?.font.pointSize)!) } else { self.leftButton.backgroundColor = Constants.BOOL_BUTTON.disabled self.leftButton.titleLabel?.font = UIFont(name: Constants.FONTS.regular, size: (self.leftButton.titleLabel?.font.pointSize)!) } } } ,但似乎18:39:12.590 [ForkJoinPool.commonPool-worker-1] DEBUG reactor.core.publisher.Operators - Duplicate Subscription has been detected java.lang.IllegalStateException: Spec. Rule 2.12 - Subscriber.onSubscribe MUST NOT be called more than once (based on object equality) at reactor.core.Exceptions.duplicateOnSubscribeException(Exceptions.java:162) at reactor.core.publisher.Operators.reportSubscriptionSet(Operators.java:502) at reactor.core.publisher.Operators.setOnce(Operators.java:607) at reactor.core.publisher.EmitterProcessor.onNext(EmitterProcessor.java:245) at de.schauder.reactivethreads.demo.StackoverflowQuicky.lambda$null$2(StackoverflowQuicky.java:54) at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110) at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:557) at de.schauder.reactivethreads.demo.StackoverflowQuicky.lambda$main$3(StackoverflowQuicky.java:52) 不是线程安全的,我强烈怀疑这是导致丢失事件的原因。

  

我们如何确保在程序结束前处理所有消息?

我会使用两个单独的EmitterProcessoronNext。另外我认为你不需要倒计时锁。

Producers

请注意我的评论:

当订阅者无法足够快地处理所有事件时,

merge会导致public static void main(String[] args) { AtomicLong counter = new AtomicLong(); AtomicLong batch = new AtomicLong(); EmitterProcessor<String> processor1 = EmitterProcessor.create(); EmitterProcessor<String> processor2 = EmitterProcessor.create(); Thread thread1 = constructThread(processor1); Thread thread2 = constructThread(processor2); Flux<List<String>> flux = processor1.mergeWith(processor2) .buffer(7) .onBackpressureError() .publishOn(Schedulers.immediate()) .doOnNext(it -> { counter.addAndGet(it.size()); System.out.println(batch.incrementAndGet() + " : Batch: " + it.size()); }).doOnComplete(() -> { System.out.println("Total count: " + counter.get()); }); thread1.start(); thread2.start(); flux.blockLast(); } private static Thread constructThread(EmitterProcessor<String> processor) { return new Thread(() -> { IntStream.range(1, 1001).forEach(it -> { processor.onNext("Message2-" + it); }); processor.onComplete(); }); } 发出错误,因此这可以解释不匹配,但您会看到异常。