It seems like these two terms are used interchangeably. Yet, there also seems to be some difference that I'm struggling to put my finger on. Is there a difference?
A continuation is the implicit parameter that the Kotlin compiler passes to any suspend function when compiling it. It is represented by a basic contract: interface Continuation<in T> { abstract val context: CoroutineContext abstract fun resumeWith(result: Result<T>) }
A coroutine is a concurrency design pattern that you can use on Android to simplify code that executes asynchronously. Coroutines were added to Kotlin in version 1.3 and are based on established concepts from other languages.
Kotlin launch vs async coroutinesThe launch launches a new coroutine concurrently with the rest of the code, which continues to work independently. The async creates a coroutine and can return the result of the asynchronous task. Start a coroutine that returns some result.
Coroutines are computer program components that generalize subroutines for non-preemptive multitasking, by allowing execution to be suspended and resumed. Coroutines are well-suited for implementing familiar program components such as cooperative tasks, exceptions, event loops, iterators, infinite lists and pipes.
It's true, these two are quite closely related. To resume a coroutine, you actually call continuation.resume()
.
Each coroutine has its associated continuation object. Actually, you don't need anything else but that object, it contains the complete state of the coroutine.
To a certain degree, Kotlin uses "coroutine" to also include the coroutine context, which gives the coroutine the knowledge how exactly to suspend itself, where to keep the continuation while suspended, and how to resume (dispatch) it later. But you can also use the Unconfined
coroutine context, which is almost as good as no context at all, and be in total control of resumption with nothing but the continuation object being preserved:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
var continuation: Continuation<Unit>? = null
fun main(args: Array<String>) {
GlobalScope.launch(Dispatchers.Unconfined) {
println("Suspending")
suspendCoroutine<Unit> { cont ->
continuation = cont
}
println("Resumed!")
}
println("After launch")
continuation!!.resume(Unit)
println("After continuation.resume(Unit)")
}
Here you can see that we reproduced the whole suspend-resume scenario while keeping nothing but the Continuation
object.
My conclusion is that, due to the features of Kotlin's coroutine design (especialy the fact that they are stackless), there's a blurry line between the concepts of "coroutine" and "continuation".
Coroutines are procedures that take turns doing their task and then suspend to give control to the other coroutines in the group, and resume task.
Continuation is the stack that controls the flow of the program, that allows it to skip into different parts of your program. You could use it to control the flow including coroutine like a global switch
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With