Kotlin coroutine principle

1 What is a coroutine

Lightweight threads, kotlin provides coroutine coroutine library after 1.3 version, a solution to simplify asynchronous task processing .

2 Why use coroutines

2.1 Simplify code and increase readability

Using coroutines can write asynchronous tasks with multiple dependencies in a concise, intuitive and highly readable way.

If you don’t use coroutines, the general asynchronous way?

  • Callback by Callback
  • Use AsyncTask
  • Call by chain
    < The CompletableFuture
    provided by strong>java8 uses the RXJava chain to implement multiple dependent asynchronous tasks, which can solve the problem of callback nesting. The callback callback is more readable.
  • Start a new thread
    ……

2.2 Use threads reasonably to reduce performance loss

  • The coroutine depends on the use of threads, suspending the coroutine will not block the thread, subsequent execution and reuse, lightweight
  • In the default thread pool of the coroutine, the processing logic Prefer to add tasks to the task queue of the current thread instead of opening a new worker thread
  • In the case of multiple cpu, no more than cpu will be opened >Number of threads and can snatch tasks from the task queues of other threads, maximizing the reuse of existing worker threads.

3 How to use coroutines

3.1 Coroutine scope

AssociationA program is a framework for managing and running asynchronous tasks, so it needs a running environment, also called the scope of the coroutine. In this scope, the coroutine can be used to execute asynchronous tasks.

(1) Global environment

GlobalScope. launch {}

GlobalScope represents the global scope of the coroutine. The coroutine started in this scope is a top-level coroutine without a parent task, and the scope does not have a Job object, so it is impossible to cancel the entire scope. () operation,

So if you don’t manually cancel each task, these tasks will run all the time, which may lead to problems such as memory leaks.

(2) Local environment

CoroutineScope(Dispatchers.Main).launch {}
Usually, a coroutine scope is implemented by creating a CoroutineScope, and a dispatcher can be specified , you can cancel all ongoing tasks under this scope.

3.2 Coroutine dispatcher

kotlin provides some default Dispatcher:

Name Description
Dispatchers.IO worker thread pool, dependent For Dispatchers.Default, the maximum number of parallel tasks is supported
Dispatchers.Main The main thread is defined differently on different platforms, so it is necessary to introduce related Dependency, such as the Android platform, needs to use a handler containing MainLooper to dispatch to the main thread
Dispatchers.Default Dispatchers.Default
Dispatchers.Unconfined There is no designated dispatch thread, it will be determined according to the online environment at runtime

Common 1 and 2

3.3 Start coroutine task

(1) For a scope object, launch and async are commonly used to create coroutines.
CoroutineScope(Dispatchers.IO).launch { }
CoroutineScope(Dispatchers.IO).async { }
The biggest difference between the two is that async will create a Deferred coroutine, which can be used to wait for the coroutine to finish executing before performing subsequent operations.

(2) Internal coroutine

CoroutineScope(Dispatchers.IO).launch {
async {
}
}

Inside a coroutine, sub-coroutines can also be created.

(3) Change the execution environment of the coroutine task
If the IO thread executes an asynchronous request, the data will be displayed on the main thread after it returns.

CoroutineScope(Dispatchers.IO).launch {
val dataJob = async {
//request data
}
async(Dispatchers. Main) {
//prepare
val data = dataJob. await()
//display with data
}
}
}

5. Coroutine suspension
Coroutines can complete asynchronous tasks sequentially, so when waiting for the completion of the previous coroutine task, the current coroutine needs to be suspended (without blocking the thread)

CoroutineScope(Dispatchers.IO).launch {
val dataJob = async {
//request data
}
withContext(Dispatchers. Main) {
//prepare
val data = dataJob. await()
//display with data
}
//do some post async job after display data
async{ }
}

withContext() method, in addition to specifying the task of starting the coroutine, can also suspend the current coroutine, that is, the coroutine of the external launch, until the coroutine started by withContext After the task is completed, the external launch coroutine will be resumed and the following async statement will be executed.

Use the suspend keyword

CoroutineScope(Dispatchers.IO).launch {
//prepare
val data = getData()
//display with data
}
//Suspend the current coroutine
private suspend fun getData() = suspendCoroutine {
Call().addCallback(object : Callback {
override fun onCall(res: String) {
//Resume coroutineit. resume(res)
}
})
}

Use the suspend keyword to indicate that the method can be suspended, called the suspend function suspendCoroutine method, which will suspend the current coroutine and return the suspended coroutine to the code block parameter, the code block executes custom logic.

4 Coroutine Implementation Principle

4.1 Fundamentals

Three Musketeers: Coroutine scope, dispatcher, coroutine

Simplify structural relationships:

Detailed relationship diagram:

Basic process: Start the coroutine in the scope, scheduler schedules, if the coroutine is suspended, schedule other coroutines or execute other main coroutine code

Leave a Reply

Your email address will not be published. Required fields are marked *