Rx java 接收运营商的执行顺序
我试图弄清楚Rx操作员的执行顺序 我所知道的是,最后一个是create操作符,也就是说,在订户出现之前,可观察对象不会创建(冷可观察) 因此,我编写了以下代码来测试这种行为:Rx java 接收运营商的执行顺序,rx-java,Rx Java,我试图弄清楚Rx操作员的执行顺序 我所知道的是,最后一个是create操作符,也就是说,在订户出现之前,可观察对象不会创建(冷可观察) 因此,我编写了以下代码来测试这种行为: public static void main(String[] args) throws InterruptedException { test(Schedulers.immediate()); test(Schedulers.computation()); ExecutorService ex
public static void main(String[] args) throws InterruptedException {
test(Schedulers.immediate());
test(Schedulers.computation());
ExecutorService executor = Executors.newCachedThreadPool();
test(Schedulers.from(executor));
executor.shutdown();
test(Schedulers.io());
test(Schedulers.newThread());
test(Schedulers.trampoline());
}
static void test(Scheduler scheduler) throws InterruptedException {
System.out.printf("-------%s--------\n", scheduler);
Observable<Integer> create = Observable.create(c -> {
c.onNext(1);
c.onCompleted();
print("CREATE");
});
create
.subscribeOn(scheduler)
.observeOn(scheduler) .map(e -> { print("MAP"); return e * 2; })
.observeOn(scheduler) .subscribe(a -> { print("SUBSCRIBE");});
TimeUnit.MILLISECONDS.sleep(200);
}
static synchronized void print(String s) {
System.out.printf("%s %s\n", s, Thread.currentThread());
}
它同时显示立即调度程序
和蹦床调度程序(都在主线程上运行),以我期望的正确方式执行
但是其他调度器是不同的(但是我正在同步方法print
,这意味着我正在防止std输出发生争用情况)
那么,为什么会发生这种情况呢?immediate
和trampoline
调度程序使用当前(单个)线程,因此严格定义了执行顺序
所有其他调度程序都是多线程的。您可以将三个任务调度到三个不同的线程
MAP应始终位于SUBSCRIBE之前,因为SUBSCRIBE仅在MAP完成后调度(MAP()的结果传递给subscriber)
除此之外,绝对不能保证任务按什么顺序序列化(通过打印函数)。因为您的可观察对象是冷链,所以在调用subscribe之前不会启动
当您调用subscribe-chain时,启动并首先调用rx.Observable.OnSubscribe#call
,然后当您调用rx.observator#onNext
时,将值提交给chain。因为您指定了调度程序,调用发布到另一个线程的map
,而主线程有时间(或没有时间)完成rx.Observable.OnSubscribe#call
如果将print(“CREATE”)
移动到rx.Observer\onNext
上方,则序列将始终为CREATE->MAP->SUBSCRIBE
在这种情况下,始终在订阅之前映射。如果所有内容都在一个线程中运行,则CREATE是最后一个线程,其他线程处于未定义位置。由于线程切换,位置未定义
根据评论更新
为什么在映射线程之前创建订阅线程
每个操作符将可观察的对象包装成另一个并返回它们
调用subscribe()
调用rx.Observable.OnSubscribe时#调用上次创建的Observable
然后处理通过堆栈执行的操作
rx.internal.operators.OnSubscribeMap#call
rx.internal.operators.OperatorObserveOn#call
rx.internal.operators.OnSubscribeMap#call
rx.internal.operators.OperatorSubscribeOn#call
...
如果您查看操作员观察
(代码剪切)
公共最终类运算符observeOn实现运算符{
公共运算符ObserveOn(调度程序、布尔延迟错误、int-bufferSize){
this.scheduler=调度程序;
this.delayError=delayError;
this.bufferSize=(bufferSize>0)?bufferSize:RxRingBuffer.SIZE;
}
@凌驾
publicsubscriberTanks;我刚刚注意到按照以下顺序创建的线程:(subscribe,map,create)-基于线程编号。但是否应该像主线程案例中那样映射susbscibe create?@MuhammadHewedy创建线程的顺序并不重要。无论如何,无法保证特定的顺序。这是多线程的本质。您是否收到相同的结果(所有调度程序的顺序相同)每次运行程序时?请尝试并检查5-10次。无论创建与否;那么为什么要在上面的映射线程之前创建订阅线程?在案例2、3、4、5(除了第一个和最后一个)中,我没有看到任何情况下订阅在映射线程之前,SUBSCRIBE的线程编号在MAP的线程编号之前;MAP的线程编号之前;MAP的线程编号之前执行(实际的线程运行顺序不是我要说的)首先被误解了。这是因为observeOn的堆栈(后进先出)请参阅rx.internal.operators.OperatorObserveOn#call我认为很难在注释中解释。每次调用observeOn时,它都会创建新的observeable,当您调用subscribe流程时,我认为代码更好。从observeOn开始,深入了解
rx.internal.operators.OnSubscribeMap#call
rx.internal.operators.OperatorObserveOn#call
rx.internal.operators.OnSubscribeMap#call
rx.internal.operators.OperatorSubscribeOn#call
...
public final class OperatorObserveOn<T> implements Operator<T, T> {
public OperatorObserveOn(Scheduler scheduler, boolean delayError, int bufferSize) {
this.scheduler = scheduler;
this.delayError = delayError;
this.bufferSize = (bufferSize > 0) ? bufferSize : RxRingBuffer.SIZE;
}
@Override
public Subscriber<? super T> call(Subscriber<? super T> child) {
if (scheduler instanceof ImmediateScheduler) {
// avoid overhead, execute directly
return child;
} else if (scheduler instanceof TrampolineScheduler) {
// avoid overhead, execute directly
return child;
} else {
ObserveOnSubscriber<T> parent = new ObserveOnSubscriber<T>(scheduler, child, delayError, bufferSize);
parent.init();
return parent;
}
}
/** Observe through individual queue per observer. */
static final class ObserveOnSubscriber<T> extends Subscriber<T> implements Action0 {
public ObserveOnSubscriber(Scheduler scheduler, Subscriber<? super T> child, boolean delayError, int bufferSize) {
this.child = child;
this.recursiveScheduler = scheduler.createWorker();
this.delayError = delayError;
this.on = NotificationLite.instance();
int calculatedSize = (bufferSize > 0) ? bufferSize : RxRingBuffer.SIZE;
// this formula calculates the 75% of the bufferSize, rounded up to the next integer
this.limit = calculatedSize - (calculatedSize >> 2);
if (UnsafeAccess.isUnsafeAvailable()) {
queue = new SpscArrayQueue<Object>(calculatedSize);
} else {
queue = new SpscAtomicArrayQueue<Object>(calculatedSize);
}
// signal that this is an async operator capable of receiving this many
request(calculatedSize);
}
}
}