-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Closed
Labels
Description
What's the difference between subscribe
and unsafeSubscribe
?
The javadoc mentions that unsafeSubscribe
should only be used for Observable.Operator
, I'm assuming that includes Observable.OnSubscribe
. Also, it briefly mentions nested subscriptions but it doesn't explain the difference in behavior of subscribe
and unsafeSubscribe
.
Also, is there guidance on when Subscribers.wrap
should be used?
Here's a snippet that I thought would behave the same, however unsafeSubscribe
is working and subscribe
is timing out.
public static Observable<Long> foo() {
return Observable.create(subscriber -> {
Observable.timer(1, TimeUnit.MILLISECONDS)
.unsafeSubscribe(Subscribers.wrap(subscriber));
});
}
public static Observable<Long> foo2() {
return Observable.create(subscriber -> {
Observable.timer(1, TimeUnit.MILLISECONDS)
.subscribe(Subscribers.wrap(subscriber));
});
}
public static void main(String[] args) {
long result = foo().flatMap(value -> foo())
.timeout(1, TimeUnit.SECONDS)
.toBlocking().single();
System.out.println("result = " + result);
long result2 = foo2().flatMap(value -> foo2())
.timeout(1, TimeUnit.SECONDS)
.toBlocking().single();
System.out.println("result2 = " + result2);
}
result = 0
Exception in thread "main" java.lang.RuntimeException: java.util.concurrent.TimeoutException
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:455)
at rx.observables.BlockingObservable.single(BlockingObservable.java:331)
at Foo.main(Foo.java:39)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.util.concurrent.TimeoutException
at rx.internal.operators.OperatorTimeoutBase$TimeoutSubscriber.onTimeout(OperatorTimeoutBase.java:169)
at rx.internal.operators.OperatorTimeout$1$1.call(OperatorTimeout.java:42)
at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
akarnokd commentedon Sep 14, 2015
Hello,
the difference is that
subscribe
wraps theSubscriber
into aSafeSubscriber
which captures exceptions thrown from the wrapped Subscriber'sonXXX
methods and unsubscribes both the upstream and downstream on a terminal event.unsafeSubscribe
doesn't do this and is mainly there to avoid the wrapping overhead as much as possible.What happens here with
foo2
is that this downstream-directed unsubscription fromSafeSubscriber
cancels the merge operation which then cancels the innerfoo2
call and simply stops emitting anything (not even terminal events) and the next operator - timeout - will time out.Generally, I'd warn against using
create
to roll your own source because there are subtle and less-subtle things that can go wrong.vadims commentedon Sep 14, 2015
Thanks for the explanation, I think the javadoc could be improved to mention this.