natario1
12/19/2022, 12:41 PMclass CustomDispatcher(private val parent: CoroutineDispatcher) : CoroutineDispatcher() {
// needs to be true so that dispatch is called
override fun isDispatchNeeded(context: CoroutineContext): Boolean = true
override fun dispatch(context: CoroutineContext, block: Runnable) {
// do some stuff, then
if (parent.isDispatchNeeded(context)) parent.dispatch(context, block)
else block.run()
}
}
• Is this safe? Calling block.run() synchronously, asking for isDispatchNeeded
during `dispatch`…
• Should I do something about dispatchYield
?
I’m asking because some dispatchers (Unconfined…) seem to communicate with the rest of the coroutine machinery in special ways which I might be breaking.Sam
12/19/2022, 1:02 PMThis method must not immediately call. Doing so may result in StackOverflowError when dispatch is invoked repeatedly, for example whenblock
is called in a loop. In order to execute a block in place, it is required to return false fromyield
and delegate the dispatch implementation to Dispatchers.Unconfined.dispatch in such cases. To support this, the coroutines machinery ensures in-place execution and forms an event-loop to avoid unbound recursion.isDispatchNeeded
Sam
12/19/2022, 1:03 PMdispatch
methodnatario1
12/19/2022, 1:21 PMit is required to return false fromThanks! But if I return false fromand delegate the dispatch implementation to Dispatchers.Unconfined.dispatch in such cases.isDispatchNeeded
isDispatchNeeed
, I won’t even get the dispatch call so can’t delegate to unconfined. Maybe it means to return false as the preferred solution or, if not possible, do Unconfined.dispatch?natario1
12/19/2022, 1:26 PMDispatchers.Unconfined.dispatch function can only be used by the yield function. If you wrap Unconfined dispatcher in your code, make sure you properly delegate isDispatchNeeded and dispatch calls
.Sam
12/19/2022, 1:49 PMfalse
from isDispatchNeeded
, the continuation automatically runs unconfined without you needing to do anything else. Maybe you just need to have your isDispatchNeeded
function delegate to parent.isDispatchNeeded
?natario1
12/19/2022, 1:52 PMdispatch()
calls to run some code there (removed in my snipped). I’m starting to think that it’s not possibleSam
12/19/2022, 2:06 PMdispatch
it might already be too late.natario1
12/19/2022, 2:12 PMblock
starts and after it ends, so I’m wrapping it in another Runnable
Sam
12/19/2022, 2:16 PMclass CustomInterceptor(private val delegate: CoroutineDispatcher): ContinuationInterceptor {
override val key: CoroutineContext.Key<*> = ContinuationInterceptor.Key
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> {
return delegate.interceptContinuation(object: Continuation<T> {
override val context: CoroutineContext = continuation.context
override fun resumeWith(result: Result<T>) {
// do stuff before
continuation.resumeWith(result)
// do stuff after
}
})
}
}
Sam
12/19/2022, 2:22 PMRunnable
that gets passed to the dispatcher is actually the same DispatchedContinuation
object that is returned by dispatcher.interceptContinuation
blob think smart. So by intercepting it before passing it to the dispatcher, the before/after code added here ends up inside that Runnable
.natario1
12/19/2022, 2:28 PMnatario1
12/19/2022, 2:29 PMSam
12/19/2022, 2:30 PMresumeWith
runs the continuation directly. The behaviour that you described, where resumeWith
schedules work on the dispatcher, is the behaviour of the continuation after it has been intercepted by the dispatcher.Sam
12/19/2022, 2:34 PMclass BrokenCustomInterceptor(private val delegate: CoroutineDispatcher): ContinuationInterceptor {
override val key: CoroutineContext.Key<*> = ContinuationInterceptor.Key
override fun <T> interceptContinuation(continuation: Continuation<T>): Continuation<T> {
val intercepted = delegate.interceptContinuation(continuation)
return object: Continuation<T> {
override val context: CoroutineContext = intercepted.context
override fun resumeWith(result: Result<T>) {
// do stuff before scheduling the task
intercepted.resumeWith(result)
// do stuff after scheduling, but maybe before actually running it!
}
}
}
}
🙅 ☝️ don’t do this 😄natario1
12/19/2022, 2:47 PM