What does the suspend function mean in a Kotlin Coroutine?

前端 未结 7 2103
不知归路
不知归路 2020-11-27 10:19

I\'m reading Kotlin Coroutine and know that it is based on suspend function. But what does suspend mean?

Coroutine or function gets

7条回答
  •  北海茫月
    2020-11-27 10:41

    To understand what exactly it means to suspend a coroutine, I suggest you go through this code:

    import kotlinx.coroutines.Dispatchers.Unconfined
    import kotlinx.coroutines.launch
    import kotlinx.coroutines.runBlocking
    import kotlin.coroutines.Continuation
    import kotlin.coroutines.resume
    import kotlin.coroutines.suspendCoroutine
    
    var continuation: Continuation? = null
    
    fun main() = runBlocking {
        launch(Unconfined) {
            val a = a()
            println("Result is $a")
        }
        10.downTo(0).forEach {
            continuation!!.resume(it)
        }
    }
    
    suspend fun a(): Int {
        return b()
    }
    
    suspend fun b(): Int {
        while (true) {
            val i = suspendCoroutine { cont -> continuation = cont }
            if (i == 0) {
                return 0
            }
        }
    }
    

    The Unconfined coroutine dispatcher eliminates the magic of coroutine dispatching and allows us to focus directly on bare coroutines.

    The code inside the launch block starts executing right away on the current thread, as a part of the launch call. What happens is as follows:

    1. Evaluate val a = a()
    2. This chains to b(), reaching suspendCoroutine.
    3. Function b() executes the block passed to suspendCoroutine and then returns a special COROUTINE_SUSPENDED value. This value is not observable through the Kotlin programming model, but that's what the compiled Java method does.
    4. Function a(), seeing this return value, itself also returns it.
    5. The launch block does the same and control now returns to the line after the launch invocation: 10.downTo(0)...

    Note that, at this point, you have the same effect as if the code inside the launch block and your fun main code are executing concurrently. It just happens that all this is happening on a single native thread so the launch block is "suspended".

    Now, inside the forEach looping code, the program reads the continuation that the b() function wrote and resumes it with the value of 10. resume() is implemented in such a way that it will be as if the suspendCoroutine call returned with the value you passed in. So you suddenly find yourself in the middle of executing b(). The value you passed to resume() gets assigned to i and checked against 0. If it's not zero, the while (true) loop goes on inside b(), again reaching suspendCoroutine, at which point your resume() call returns, and now you go through another looping step in forEach(). This goes on until finally you resume with 0, then the println statement runs and the program completes.

    The above analysis should give you the important intuition that "suspending a coroutine" means returning the control back to the innermost launch invocation (or, more generally, coroutine builder). If a coroutine suspends again after resuming, the resume() call ends and control returns to the caller of resume().

    The presence of a coroutine dispatcher makes this reasoning less clear-cut because most of them immediately submit your code to another thread. In that case the above story happens in that other thread, and the coroutine dispatcher also manages the continuation object so it can resume it when the return value is available.

提交回复
热议问题