-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
observeOn doesn't behave as expected (Clojure) #625
Comments
I believe this is related to a bug where We should be able to unsubscribe from a
The file contains this: The If you change to use (-> (Observable/interval 100 TimeUnit/MILLISECONDS (Schedulers/immediate))
(.take 5)
(.observeOn (Schedulers/currentThread))
(.subscribe (rx/action [v]
; this file is created, but the content do not match (*)
(spit "/tmp/tid.txt" (Thread/currentThread))
(println v))) ; this output never reaches the repl
)
; outputs to file: Thread[nREPL-worker-2,5,main] It now stays on the main thread and Generally |
Thanks for the detailed answer. The fact that Interval runs in the current thread by default is a little surprising, but I can live The example you provided does get the output to the repl (it hangs, but that's expected now) As I understand it observeOn determines where the cb is run. Since I wasn't getting Given your feedback, I expected this to work:
Which I read as: the interval runs in a new thread (Forever, for now), while the ...It doesn't block, but no output is generated. |
The
ObserveOn has no way to automatically make something jump back to the "main" thread the REPL is on. That would require the main thread offering an event-loop or something to hook into and a
The Thus, it doesn't determine anything, it just puts the work where you tell it. Thus, in your code, Here are two examples, one blocking another non-blocking: (-> (Observable/interval 100 TimeUnit/MILLISECONDS)
(.take 5)
(.subscribe (rx/action [v]
(println "non-blocking" v (java.lang.Thread/currentThread)))))
(-> (Observable/interval 100 TimeUnit/MILLISECONDS)
(.take 5)
(.toBlockingObservable)
(.forEach (rx/action [v] (println "blocking" v (java.lang.Thread/currentThread))))) The REPL shows this:
The console shows this:
If I want it to emit to the REPL I would need to have it all run on the REPL thread, then I get this:
This then causes the bug with I don't know enough about how the Clojure REPL works (I'm a beginner with Clojure) to know if there is a way to hook a Now to see how (-> (Observable/interval 100 TimeUnit/MILLISECONDS) ; run on default which is Schedulers.threadPoolForComputation()
(.take 5)
; print out the value and what thread it is on before doing `observeOn`
(.doOnNext (rx/action [v] (println "interval emitted" v "on thread" (java.lang.Thread/currentThread))))
(.observeOn (Schedulers/newThread)) ; move it to a new thread from here onwords
(.subscribe (rx/action [v]
; receive the output and show what thread it is one
(println " -> output" v "on thread" (java.lang.Thread/currentThread))))) The REPL shows:
The console shows:
If I want to emit something to the REPL without using (-> (Observable/interval 100 TimeUnit/MILLISECONDS) ; run on default which is Schedulers.threadPoolForComputation()
(.take 5)
(.observeOn (Schedulers/newThread)) ; move it to a new thread from here onwords
(.map (rx/fn [v]
; receive the output and show what thread it is one
(str " -> output " v " on thread " (java.lang.Thread/currentThread))))
(.toList)
(.toBlockingObservable)
(.single)) This now returns the
Hope this is helpful. |
/cc @daveray in case you can provide better insight (particularly regarding REPL/console output) |
That's a fantastic answer. Noting that I realize now part of the issue is that I use emacs/cider so println output in another thread ends Yes, it doesn't make sense to ask for work to be schedueled in the currentThread without something Still puzzled by how in your last example the result gets returned to the current thread. In any case that was very helpful and realizing the behavior I described is not a bug, Thanks again. |
It's the call to |
See here for more info about |
Right, but everything you've shown me so far suggests that the blocking observable will still Happy new year. |
Yes, it happens on the background thread where it is scheduled. The Outside of a REPL it might make more sense where the assignment is explicit. // this returns a non-blocking Observable and is lazy, so not running yet
Observable<Long> i = Observable.interval(100, TimeUnit.MILLISECONDS).take(5);
// this executes the above and returns a Subscription and does so asynchronously (non-blocking)
Subscription s = i.subscribe({ v -> println(v)});
// or I can block and fetch the last value
long lastValue = i.toBlockingObservable().last(); The This is what the REPL is doing in my example where it gets the list of values returned to the REPL thread itself and it blocks the REPL thread until the value is returned. The return type explains what is going on. |
* Make this config explicitly immutable * Explicit doc for config field * Temporary change, to trigger warning from sonar. * Make this config explicitly immutable * Fix few other sonar complaints * Disable non-relevant check in sonar * Remove unused import * Propagate right info about thread interruption to callers via exceptions and Thread.interrupted flag * Fixes after merge with master * Additional tests and code cleanup * Tests fix * Update documentation about thread interruption contract. Update release notes. * Make common exception type for RateLimiter and Bulkhead * Code review comments fixed
So,
Observable/interval
spawns a new thread and the subscribed callback is invoked in that thread by default. I need to useobserveOn
to ensure the cbis invoked in the current thread so that the
println
output makes it to the repl./tmp/tid.txt
does get created, so the cb is called but the println outputnever makes it to the repl.
If i schedule
Observable/interval
in the current thread (commented out) theoutput is visible (though the repl hangs afterwards for some reason), but
the
observeOn
itself doesn't seem to do the job it's meant to.The contents of /tmp/tid/txt don't match the current thread reported
by the println either.
Is this a bug or am I doing something wrong?
The text was updated successfully, but these errors were encountered: