suspendCoroutine
is a low-level primitive that is designed for conversion of callbacks into suspending functions. You should not use suspendCoroutine
in your high-level code, precisely because invocation of suspendCoroutine
exposes coroutine implementation details (a Continuation
object) and can break the illusion of sequential execution in the way you’ve shown.
In particular, you should not mix your business-logic with suspendCoroutine
invocations. Your high-level code should never work with Continuation
objects directly. Continuation
is exposed in Kotlin via suspendCoroutine
only for the purpose of implementing low-level suspending functions.
Let us rewrite exec2
from your first example with this principle in mind:
suspend fun exec2() {
println("exec2 started")
exec2Cancel()
Thread.sleep(1000)
println("exec2 finished")
}
suspend fun exec2Cancel() = suspendCoroutine<Unit> { cont ->
thread {
println("exec2 canceled")
cont.resumeWithException(Exception("oops"))
}
}
Now exec2
does not use suspendCoroutine
and it indeed executes sequentially just as it is supposed to. In particular, because exec2Cancel
suspending function asynchronously completes with exception, the invocation of exec2
also completes with exception, never reaching “exec2 finished” line.
Because a code within a
suspendCoroutine
function can be another long-running Coroutine which can decide by itself whether to run its code in current or parallel thread
No. Code in suspendCoroutine
cannot be a coroutine itself. The block of code that suspendCoroutine
accepts is not a suspending function. Basically, the invocation of suspendCoroutine
breaks out of coroutine into a regular non-suspending code where you are completely on your own in managing your asynchrony and concurrency via call-backs and other means.
Sorry, but I did not quite got what you were trying to achieve with your second example. Can you elaborate, please?