在RxJava中实现REAL背压的最佳实现

时间:2016-11-12 11:44:22

标签: java multithreading rx-java reactive-programming

嗯,RxJava中的背压不是真正的背压,而只是忽略了一些元素。

但是,如果我不能放松任何元素,我需要以某种方式减慢emition?

RxJava不会影响元素emition,因此开发人员需要自己实现它。但是如何?

最简单的方法就是使用一些计数器来增加emition并减少完成。

就像那样:

public static void sleep(int ms) {
    try {
        Thread.sleep(ms);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) throws InterruptedException {

    AtomicInteger counter = new AtomicInteger();

    Scheduler sA = Schedulers.from(Executors.newFixedThreadPool(1));
    Scheduler sB = Schedulers.from(Executors.newFixedThreadPool(5));

    Observable.create(s -> {
        while (!s.isUnsubscribed()) {
            if (counter.get() < 100) {
                s.onNext(Math.random());
                counter.incrementAndGet();
            } else {
                sleep(100);
            }
        }
    }).subscribeOn(sA)
            .flatMap(r ->
                    Observable.just(r)
                            .subscribeOn(sB)
                            .doOnNext(x -> sleep(1000))
                            .doOnNext(x -> counter.decrementAndGet())
            )
            .subscribe();
}

但我认为这种方式很差。有没有更好的解决方案?

2 个答案:

答案 0 :(得分:3)

  

嗯,RxJava中的背压不是真正的背压

RxJava的背压实施是通过请求渠道在后续生产者和消费者之间进行的非阻塞合作。消费者通过request()请求一些元素,并且制作者通过onNext创建/生成/发出最多该项数量,有时会在onNext之间延迟。

  

但只忽略一些元素集。

只有当您明确告诉RxJava丢弃任何溢出时才会发生这种情况。

  

RxJava不会影响元素emition,因此开发人员需要自己实现它。但是如何?

使用Observable.create需要有关如何实施非阻塞背压的高级知识,实际上不建议图书馆用户使用。 RxJava有很多方法可以为您提供背压驱动流程而不会出现复杂情况:

Observable.range(1, 100)
.map(v -> Math.random())
.subscribeOn(sA)
.flatMap(v ->
    Observable.just(v).subscribeOn(sB)
    .doOnNext(x -> sleep(1000))
)
.subscribe();

Observable.create(SyncOnSubscribe.createStateless(
    o -> o.onNext(Math.random())
)
.subscribeOn(sA)
...

答案 1 :(得分:-1)

正如您所说,这实际上与RxJava无关 如果您必须最终处理所有事件,但您希望按照自己的步调进行,请使用队列:

    ExecutorService emiter = Executors.newSingleThreadExecutor();
    ScheduledExecutorService workers = Executors.newScheduledThreadPool(4);
    BlockingQueue<String> events = new LinkedBlockingQueue<>();


    emiter.submit(() -> {
       System.out.println("I'll send 100 events as fast as I can");

        for (int i = 0; i < 100; i++) {
            try {
                events.put(UUID.randomUUID().toString());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });

    workers.scheduleWithFixedDelay(
            () -> {
                String result = null;
                try {
                    result = events.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(String.format("I don't care, got %s only now", result));
            }, 0, 1, TimeUnit.SECONDS
    );