David Glasser
08/27/2019, 10:44 PMsuspendCoroutine
and suspendCancellableCoroutine
when writing a wrapper around an external callback-based API.
My original understanding was that the difference between the two is just whether or not the continuation you get access to in the block has methods that lets the block you write right there cancel it. So you should use the latter if the API you're wrapping has some way of indicating that it cancelled so that you would want to cancel the suspended coroutine, but otherwise there's no need to use the longer-named function.
But when I test these out,
fun main() = runBlocking {
withTimeout(10) {
suspendCancellableCoroutine { continuation: CancellableContinuation<Unit> -> }
}
}
throws a TimeoutCancellationException (as I expected), but
fun main() = runBlocking {
withTimeout(10) {
suspendCoroutine { continuation: Continuation<Unit> -> }
}
}
appears to hang, which surprises me.
Does that imply that when you run suspendCoroutine then your current coroutine can't be cancelled "from above"? In that case, why would you ever use suspendCoroutine instead of suspendCancellableCoroutine?octylFractal
08/27/2019, 10:50 PMsuspendCoroutine
doesn't check for cancellation at all, unless you do it within the block itself using `isActive`/calling a cancellable suspend point.
The reason there are both, is that cancellation isn't a concept in the stdlib coroutines, that's purely part of the kotlinx coroutines library, along with Job, CoroutineScope, etc.suspendCoroutine
is useful if you want to suspend in a non-Job scope, such as with sequence {}
David Glasser
08/27/2019, 10:56 PMoctylFractal
08/27/2019, 10:58 PMZach Klippenstein (he/him) [MOD]
08/28/2019, 5:10 PMwhether or not the continuation you get access to in the block has methods that lets the block you write right there cancel it.It’s the other way around –
suspendCancellableCoroutine
lets you notify the API you’re wrapping that the coroutine was cancelled (via its Job). That’s why your second example hangs – withTimeout
tries to cancel the coroutine, which is suspended, but since you haven’t opted into cancellation it can’t be cancelled.David Glasser
08/28/2019, 5:48 PMZach Klippenstein (he/him) [MOD]
08/28/2019, 6:01 PMrunBlocking
will block until all child coroutines have finished, and since your (uncancellable) coroutine never finishes, it never returns.