kotlin-筆記05-協程中suspend原理Suspend functions - Kotlin Vocabulary 相關詞彙 youtube視頻鏈接 協程Codelab 前言

相關詞彙

a finite state:suspend 函數使用1-2-3 3個狀態
Continuation:協程掛起函數之間相互通信的方式是Continuation接口對象。
recursively:遞歸調用


youtube視頻鏈接

Kotlin中的協程簡化了Android上的異步操作。在這個視頻中,我們將更深入地瞭解爲什麼協程是重要的,它們在幕後是如何工作的,協程如何在不阻塞線程的情況下掛起,等等!

Suspend functions - Kotlin Vocabulary

協程Codelab

在 Android 應用中使用 Kotlin 協程


前言

Coroutine are a future of Kotlin that simplify asynchronous operations on Android.
A new suspend modifer was introduced in the language,and it is used for functions that need to be run inside the coroutine.
In this video ,I will tell you more about why coroutines are important and how they work under the hood.
This will help you better understand why a suspend function won't return until all the work that it has started has completed, and also how a coroutine can suspend without blocking threats.
If you learn something new,like the video and subscribe, but only if you think we're earned it.


Use coroutine to manage asynchronous tasks that might otherwise block the main thread and cause you app to freeeze.
Coroutines are also helpful to replace callback-based APIs with imperative looking code.
Let's see an example of asynchronous code that uses callbacks.

Here ,we have the function,loginUser that,after making an echo request to get user information from the internet,it saves the result to the local database and returns the result of that call--all of the using callbacks.

The result of the computation is returns using the userResult callback that is passed in as parameter of the function.

Code that heavily uses callbacks can become hard to read and understand.
Kotlin coroutines let you convert callback-based code to sequential code.
Code read in sequentianlly is typically easier to read and ,unlike callbacks,coroutines provide an easy way to swap between threads and handle exceptions.

See the same function return with coroutines.

We added the suspend modifer to the function,and now it returns user instead of having that callback we used to pass in as a parameter.
As you can see from the wiggly icon in the code there,the other functions call from the suspend function body are also suspend functions.

That suspend modifer tells the compiler that this function needs to be executed inside a coroutine. As a developer,you can think of a suspend function as a regular function whose execution might be suspended and resumed at some point.

If you're new to coroutines in Android and want to learn more about them, I would recommend going throught the coroutine Codelabs first.
But what's the compiler actually doing under the hood when we mark the function as suspend?
Under the hood,the kotlin compiler takes suspended functions and coverts them to an optimized version of callbacks using a finite state machine.

So yes ,you are right,the kotlin compiler will write those callbacks for you.


There way suspend functions communicate with each other is continueation objects.
A continuation is just a generic callback interface with some extra information.

  • Context will be the CoroutineContext to be used in that continuation.
  • resumeWith resumes execution of the coroutine with a result that can contian either a value,which is the result of the computation that caused the suspension, or an exception.

With Kotlin 1.3,you also have convenient extension functions called resume and resumeWithException that are specialized versions of the resumeWith function.

Back to our suspend function,how is compiler is going to modify it ?

It will replace the suspend modifier with an extra parmater called completion of type continuation in the function signature.
That will be used to communicate the result of the suspend function computation to the coroutine that called it ,as you can see in the code.
Also,the return type of the transformed function is unit instead of user. The user object will be returned in the added continuation parameter.

Time out.
As a disclaimer,the code we are showing will not fully match bytecode generated by the compiler.
It would be Kotlin code accurate enough to allow you to understand what's really happening internally. This representation is generated by coroutines version 1.3 and might change in future versions of the library.

Back to the code again.
The kotlin compiler will identify when the function can suspend internally. Every suspension point will be represented as a state in the finite state machine. And these states are represented with lables by the compiler.

For a better representation of the state machine, the compiler will use a when statement to implement the different states.

  • Notice that this code is incomplete, since the different states have no may to share information.

How is that problem solved?
The compiler will use the continuation parameter to do it. This is why the generic of the continuation is [inaudible] any instead of the return type of the original function that was user.
The compiler will create a private class that ,first,hold the required data ,and second,calls the loginUser function recursively to resume the execution of the function that was suspended.
Let's see what that class looks like.

Let's call that generated class,loginUserStateMachine. It is a private class that extends from CoroutineImpl,which is a subtype of continuation. In the constructor,it takes this continuation object,named completion ,that will be used to communicate back the result of this function to the function that called it .

This is the same continuation that we called before in the last state of the state machine.
But also,this class saves the variables that were declared in the original suspend function.
And there are other variable that are common for all CoroutineImples. The reuslt variable is the result from the previous continuation and label keeps the state of the state machine.

Also,it overrides the invoke suspend function that is used to resume the state machine. It will call the loginUser function to trigger the state machine again.
It calls it with just information of the continuation object.
The rest of parameters in the loginUser function signature become nullable.
At that point ,lable will be already in the next state to execute ,and the result of the previous state's continuation will be assigned.

An instance of this class is added to loginUser. The first thing it needs to do is knowing if it is the first time the function is called or if the function has resumed from a previious state.
It does it by checking if the continuation passed in is of type loginUserStateMachine or not.
If it's the first time ,it will create a new loginUserStateMachine instance and will store the completion instance received as a parameter.
If it's not ,it will just carry on executing the state machine.

For completion ,this is what the rest of the function looks like.

You can see how the rest of code uese the continuation variable to read the result of the last state of the state machine.


But also ,for every state,it checks if I never happened while this function was suspended.

In the last state, it calls resume on the continuation of the function that called this one.
And that's it. As you can see, the kotlin compiler does a lot under the hood.
Because of the implementation of the generated state machine,a suspend function won't return until all the work that it has started has completed.

Well,everything needed to resume
How can the code suspend without blocking the thread? the execution of a suspend function is in the continuation object that is passed around,so it can be resumed at any point .
That's all we have to say about suspend for now.
Thanks for watching ,and go write better Android apps with Kotlin.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章