在一个combineLatest后,我的Flowable链条没有继续运行。最后,我试图在一个单独的类中重现行为。我发现的有点令人不安:
public static void main(String[] args) throws InterruptedException {
test();
test();
Thread.sleep(10000);
}
private static void test() {
System.out.println("before");
Flowable<Integer> fa = Flowable.<Integer>generate(emitter -> emitter.onNext(1)).observeOn(Schedulers.computation()).throttleLast(1, TimeUnit.SECONDS) ;
Flowable<Integer> fb = Flowable.<Integer>generate(emitter -> emitter.onNext(2)).observeOn(Schedulers.computation()).throttleLast(1, TimeUnit.SECONDS) ;
Flowable.combineLatest(fa, fb, (a, b) -> a - b)
.subscribeOn(Schedulers.computation())
.subscribe(c -> {
System.out.println("c: " + c);
});
System.out.println("after");
}
之前/之后两次,没有任何事情发生。但是,如果我注释掉两个test()调用中的一个,它就可以了。如果我用Schedulers.io()替换Schedulers.computation(),它可以用于test()调用。
我想解释必须与每个核心有一个计算线程这一事实有关。即便如此,这种行为对我来说也没有任何意义。
任何人都可以开导我吗?使用Schedulers.io()似乎不是一个好的解决方案。顺便说一下,我使用throttleLast,因为消费者必须能够控制吞吐量。
答案 0 :(得分:1)
我不完全理解你的问题。我尝试了以下更改代码:
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import com.google.common.collect.Sets;
import io.reactivex.Flowable;
import io.reactivex.schedulers.Schedulers;
public class TestRxJava2 {
static final Queue<Integer> fa1 = new ConcurrentLinkedQueue<Integer>();
static final Queue<Integer> fb1 = new ConcurrentLinkedQueue<Integer>();
static final Queue<Integer> c1 = new ConcurrentLinkedQueue<Integer>();
static final Queue<Integer> fa2 = new ConcurrentLinkedQueue<Integer>();
static final Queue<Integer> fb2 = new ConcurrentLinkedQueue<Integer>();
static final Queue<Integer> c2 = new ConcurrentLinkedQueue<Integer>();
public static void main(String[] args) throws InterruptedException {
Flowable<Integer> f1 = test(1);
Flowable<Integer> f2 = test(2);
Flowable.zip(f1, f2, (a,b) -> a)
.blockingSubscribe();
System.out.println(fa1.size() == 10 && fa1.size() == fa2.size());
System.out.println(fb1.size() == 10 && fb1.size() == fb2.size());
System.out.println(c1.size() == 19 && c1.size() == c2.size());
System.out.println(Sets.difference(Sets.newHashSet(fa1), Sets.newHashSet(fa2)).size() == 0);
System.out.println(Sets.difference(Sets.newHashSet(fb1), Sets.newHashSet(fb2)).size() == 0);
System.out.println(Sets.difference(Sets.newHashSet(c1), Sets.newHashSet(c2)).size() == 0);
}
private static Flowable<Integer> test(int i) {
Flowable<Integer> fa = Flowable.<Integer>generate(emitter -> emitter.onNext(1))
.observeOn(Schedulers.computation())
.throttleLast(1, TimeUnit.SECONDS)
.take(10)
.scan((a, b) -> a + b)
.doOnNext(next -> {
if (i == 1) {
fa1.add(next);
} else {
fa2.add(next);
}
});
Flowable<Integer> fb = Flowable.<Integer>generate(emitter -> emitter.onNext(1))
.observeOn(Schedulers.computation())
.throttleLast(1, TimeUnit.SECONDS)
.take(10)
.scan((a, b) -> a + b)
.doOnNext(next -> {
if (i == 1) {
fb1.add(next);
} else {
fb2.add(next);
}
});
return Flowable.combineLatest(fa, fb, (a, b) -> a + b)
.subscribeOn(Schedulers.computation())
.doOnNext(next -> {
if (i == 1) {
c1.add(next);
} else {
c2.add(next);
}
})
.doOnNext(next -> System.out.println(i + "CombineLatest : " + next))
.doOnSubscribe(sb -> System.out.println(i + " subscribed"))
;
}
}
控制台输出如下:
1 subscribed
2 subscribed
1CombineLatest : 2
2CombineLatest : 2
1CombineLatest : 3
2CombineLatest : 3
1CombineLatest : 4
2CombineLatest : 4
1CombineLatest : 5
2CombineLatest : 5
1CombineLatest : 6
2CombineLatest : 6
1CombineLatest : 7
2CombineLatest : 7
1CombineLatest : 8
2CombineLatest : 8
1CombineLatest : 9
2CombineLatest : 9
1CombineLatest : 10
2CombineLatest : 10
1CombineLatest : 11
2CombineLatest : 11
1CombineLatest : 12
2CombineLatest : 12
1CombineLatest : 13
2CombineLatest : 13
1CombineLatest : 14
2CombineLatest : 14
1CombineLatest : 15
2CombineLatest : 15
1CombineLatest : 16
2CombineLatest : 16
1CombineLatest : 17
2CombineLatest : 17
1CombineLatest : 18
2CombineLatest : 18
1CombineLatest : 19
2CombineLatest : 19
1CombineLatest : 20
2CombineLatest : 20
true
true
true
true
true
true
您能否就此代码进行解释,您的问题到底是什么?
答案 1 :(得分:1)
有趣。看起来这个特殊的紧密循环设置不会让throttleLast
有机会发射。我已经在我的4核机器上多次运行你的代码,偶尔我会打印出-1
。
您可以对Scheduler
使用其他throttleLast
,例如Schedulers.single()
,以便释放computation()
Scheduler
。然而,潜在的问题是紧密循环,它可以挂钩computation
Scheduler
中的一个线程,所以如果将同一个线程分配给另一个紧密循环工作,它可能无法在一个合理的范围内执行时间。
通过添加一些doOnNext
和doOnSubscribe
来电,似乎大部分时间test-1 fa
和test-2 fb
正在发送数据但不是{分别为{1}}和test-1-fb
,因此test-2-fa
由于缺少配对而不会产生任何值。
修改强>
该问题的一个特性是combineLatest
针对生成器线程和所选发射线程之间的持续流进行了优化,在某些情况下可能会固定两个线程。通过将每个源发射和earch请求转换为自己的任务并依赖底层线程池的公平性,还可以以更加线程使用友好的方式在线程之间切换。以下自定义运算符应取消阻止您的用例。将observeOn
替换为observeOn(Schedulers.computation())
。
compose(requestObserveOn(Schedulers.computation()))