Christopher Porto
08/18/2022, 7:37 AMsuspend fun test() {
val response = bar()
println("I want this to be on same thread as it was before doing bar call")
}
suspend fun bar() {
val response = someOtherCallThatSwitchesThread()
return response
}
I figured calling suspendCoroutine
inside bar then launching new coroutine that resumes the continuation with the response would work and while it does change the thread, it doesnt go back to original.simon.vergauwen
08/18/2022, 7:42 AMsuspendCoroutine
takes care of switching back to the original thread.
I'm not sure what someOtherCallThatSwitchesThread
is doing but you probably want,
suspend fun bar() =
suspendCoroutine {
val response = someOtherCallThatSwitchesThread()
cont.resume(response)
}
Or in case someOtherCallThatSwitchesThread()
is some Java SDK library which does blocking you might want to use:
runInterruptible {
someOtherCallThatSwitchesThread()
}
Christopher Porto
08/18/2022, 7:59 AMsomeOtherCallThatSwitchesThread
is suspendable function in networking library (which launches coroutine in its own thread, or something along those lines)
So that being said since someOtherCallThatSwitchesThread
is suspendable I need to call it within a coroutine. I created a scope and did the calls in there, not sure if thats right
suspend fun bar() = suspendCoroutine {
scope.launch {
val response = someOtherCallThatSwitchesThread()
cont.resume(response)
}
}
simon.vergauwen
08/18/2022, 8:01 AMsomeOtherCallThatSwitchesThread
behaving incorrectly. The bar
definition should work, but it's definitely a patch rather than a fix for this issue.simon.vergauwen
08/18/2022, 8:02 AMwithContext(OtherContext) {
someOtherCallThatSwitchesThread()
}
This should also work, as long as OtherContext
is not the same as the context your code is running on.Christopher Porto
08/18/2022, 9:05 AMNick Allen
08/18/2022, 5:11 PMbar
? What you are asking for is only possible if the dispatcher is single threaded. You never specify if that's the case.Nick Allen
08/18/2022, 5:22 PMsuspendCouroutine
is for suspending while waiting for callback APIs, launching inside is just confusing and odd. If you want to force dispatcher to redispatch, you could try just calling yield
.Christopher Porto
08/19/2022, 1:14 AMbar
is single threaded which is why I want continuation to stay on that thread since continuation logic isnt thread safe.
someOtherCallThatSwitchesThread
is suspendable function from third party library that later on launches coroutine with multi threaded dispatcher to invoke its logic which I assume the continuation then gets passed and executes on it (which I want to avoid)
What I have works now but I agree launch inside suspendCoroutine
is a bit odd. One key thing is I require the response from someOtherCallThatSwitchesThread
to resume continuation, not sure if yield
is the solution here, kinda unfamiliarNick Allen
08/19/2022, 1:31 AMsomeOtherCallThatSwitchesThread
. The problem you are running into shouldn't be possible with the usual coroutine APIs and one or the other is breaking very fundamental assurances of coroutines if you are ending up not on the expected dispatcher. It's generally difficult to resume continuations on the wrong thread because they are almost always wrapped in a continuation that delegates to the CoroutineInterceptor
(dispatcher). If someOtherCallThatSwitchesThread
is broken, I would avoid all coroutine APIs of that library if not the entire library and log a bug so they can fix their issue.simon.vergauwen
08/19/2022, 7:22 AMIt's generally difficult to resume continuations on the wrong thread because they are almost always wrapped in a continuation that delegates to the(dispatcher)CoroutineInterceptor
suspend fun main()
starts a coroutine on the main thread, but with EmptyCoroutineContext
then you will also run into the scenario that intercepted()
doesn't bring you back to the original thread and thus context preservation breaks.simon.vergauwen
08/19/2022, 7:22 AMsingleThreadContext
should still always bring you back to the proper context if it's properly implemented. To me it looks like someOtherCallThatSwitchesThread
is broken, and is not preserving the context correctly.Christopher Porto
08/21/2022, 2:33 PMbut withThis was the case 😅 Took a look at our implementation of our custom continuation and it didnt keep context and instead usedthen you will also run into the scenario thatEmptyCoroutineContext
doesn't bring you back to the original thread and thus context preservation breaks.intercepted()
EmptyCoroutineContext
Thanks you two