The concept of coroutines was first proposed and implemented by Melvin Conway in 1963 to simplify collaboration between lexical and parsers of the COBOL compiler, which at the time described coroutines as “child threads that behave like the main program.”
Coroutines can be regarded as lightweight threads. Currently, Python, Go, Kotlin and other development languages have supported coroutines. Java can use coroutines through third-party extensions.
The comparison between threads and coroutines can be briefly described as follows:
Thread:
Threads are scheduled by the operating system, and thread switching or thread blocking is implemented by the operating system and CPU scheduling.
Coroutines:
The coroutine runs in the user mode of the operating system and relies on threads to implement it. Through the user mode program control, the operating system and CPU overhead caused by thread blocking can be minimized or avoided. Unlike threads, coroutines do not need to block the thread in which they are running when suspended. During the period of coroutine suspension, the corresponding thread can be assigned other coroutine tasks to execute, and when the coroutine task starts again after the suspension, the coroutine task will be handed over to a thread to continue execution (the period of coroutine suspension is similar to adding the coroutine task to a task queue).
The latest release of Kotlin coroutine on GitHub is 1.6.0, and the corresponding GitHub source address is github.com/Kotlin/kotl…
- Description of GlobalScope usage
- CoroutineScope usage description
A Brief description of GlobalScope usage
GlobalScope inherits from the CoroutineScope (interface). Its source code implementation is a global singleton, and because it is a singleton, its life cycle follows that of the entire application; A top-level coroutine can be launched using GlobalScope.launch.
- Examples of GlobalScope usage
- Brief description of GlobalScope
1.1 Examples for Using GlobalScope
Importing dependency packages:
The first step is to introduce the Kotlin coroutine dependent library. The latest release of Kotlin coroutine on GitHub is 1.6.0, and the corresponding GitHub source address is github.com/Kotlin/kotl…
// Coroutine core library
implementation "Org. Jetbrains. Kotlinx: kotlinx coroutines -- core: 1.6.0." "
// The coroutine Android library
implementation "Org. Jetbrains. Kotlinx: kotlinx coroutines - android: 1.6.0." "
Copy the code
Thread switching:
When globalScope. launch executes a task, switch different threads:
// ------------ Example -----------
// When GlobalScope executes a task, it switches different threads
//
// start a coroutine
var job = GlobalScope.launch(context = Dispatchers.Main) {
// TODO Main thread
}
// start a coroutine (asynchronous thread: default number of threads 64)
var job = GlobalScope.launch(context = Dispatchers.IO) {
// TODO asynchronous thread: The number of threads is 64 by default
}
// start a coroutine (asynchronous threads: the maximum number of threads is equal to the number of CPU cores)
var job = GlobalScope.launch(context = Dispatchers.Default) {
// TODO asynchronous threads: The maximum number of threads is equal to the number of CPU cores
}
// start a coroutine (current thread execution)
var job = GlobalScope.launch(context = Dispatchers.Unconfined) {
// TODO is executed by the current thread
}
// get the cancel algorithm
// job.cancel()
Copy the code
GlobalScope. Launch to use:
Globalscope. launch Performs an asynchronous network task and returns results to update the UI. In the following examples, the following keywords or methods are involved:
suspend
Key words:
When ctrip is blocked, it is used to suspend the current coroutine and save all local variables.
withContext
Methods:
Move the current coroutine to an I/O thread to perform an asynchronous operation.
// ------------ Example -----------
// GlobalScope performs an asynchronous network task and returns the result to update the UI
//
class GlobalScopeActivity : AppCompatActivity() {
//
lateinit var job: Job;
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/ / GlobalScope. Launch to use
launchGlobalScope();
}
/** * Globalscope.launch uses */
private fun launchGlobalScope(a) {
/ / GlobalScope. Launch to use
job = GlobalScope.launch(Dispatchers.Main) {
// TODO executes the main thread // main thread
GetNetData Asynchronously obtains network data
val netStr: String = getNetData() // IO thread
// return to the main threadtextView? .text = netStr// main thread}}The suspend keyword is used to suspend the current coroutine and save all local variables */
private suspend fun getNetData(a): String {
// withContext moves the current coroutine to an I/O thread to perform an asynchronous operation
return withContext(context = Dispatchers.IO) {
// TODO IO thread network request
// Http synchronous network request with a String return value
HttpAgent.get_Sync(
"https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=18701636688".null.null,
String::class.java
)
}
}
}
Copy the code
GlobalScope. Async use:
Globalscope. async Performs an asynchronous network task, returns the result and updates the UI. In the following examples, the following keywords and methods are involved:
async
Methods:
The async method starts a new coroutine;
await
Key words:
Coroutines started by async methods can use a keyword called await and wait for the time-consuming method to return the result of execution.
// ------------ Example -----------
// GlobalScope.async performs an asynchronous network task and returns the result to update the UI
//
class GlobalScopeActivity : AppCompatActivity() {
//
lateinit var job: Job;
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/ / GlobalScope. Use async
asyncGlobalScope()
}
// ---------------------GlobalScope.async-----------------------
/** * GlobalScope. Async uses: * The async method starts a new coroutine, uses a keyword called await, and waits for the result to return when the time-consuming method has finished executing. * /
private fun asyncGlobalScope(a) {
/ / GlobalScope. Use async
job = GlobalScope.launch(Dispatchers.Main) {
// TODO executes the main thread // main thread
// The first asynchronous network request
val taobaoData = async(Dispatchers.IO) { // IO thread
// TODO IO thread network request
// Http synchronous network request with a String return value
HttpAgent.get_Sync(
"https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=18701636688".null.null,
String::class.java
)
}
// The second asynchronous network request
val baiduData = async(Dispatchers.IO) { // IO thread
// TODO IO thread network request
// Http synchronous network request with a String return value
HttpAgent.get_Sync(
"https://www.baifubao.com/callback?cmd=1059&callback=phone&phone=18701636688".null.null,
String::class.java
)
}
// After both results are returned
val resultData: String = (taobaoData.await() + baiduData.await())
/ / display the UItextView? .text = resultData// main thread}}}Copy the code
1.2 Brief Description of GlobalScope
Not recommended to use GlobalScope directly?
The GlobalScope source code implementation is a global singleton (the singleton object in Kotlin is implemented by the object keyword), and the corresponding source code is as follows:
GlobalScope is a singleton
public object GlobalScope : CoroutineScope {
override val coroutineContext: CoroutineContext
get() = EmptyCoroutineContext
}
Copy the code
Because GlobalScope is a singleton, and because the GlobalScope object is not associated with the Android application lifecycle component, you need to manage the Coroutine GlobalScope creates yourself. Otherwise, a coroutine launched through GlobalScope will have the same life cycle as the entire Android application, running as long as the entire application is running and the coroutine’s task is not finished. Therefore, it is generally not recommended to use GlobalScope directly to create coroutines.
Coroutines don’t block threads, right?
As stated at the beginning of this article, during the period of coroutine suspension, the corresponding thread can be assigned to other coroutine tasks to execute, and when the coroutine task is started again after suspension, the coroutine task will be handed over to a thread to continue to execute (the period of coroutine suspension is similar to adding the coroutine task to a task queue).
Here’s a code to verify:
// Start a coroutine (IO asynchronous thread)
GlobalScope.launch(context = Dispatchers.IO) {
// Start the coroutine
Log.d(TAG, "[GlobalScope] start ")
// Suspend for 2 seconds
delay(2000)
// Continue the coroutine
Log.d(TAG, "[GlobalScope] currThread: " + Thread.currentThread().name)
// Start the coroutine
launch {
Log.d(TAG, "[launch A] Begin")
delay(400)
Log.d(TAG, "[launch A] currThread: " + Thread.currentThread().name)
Log.d(TAG, "[launch A] end")}// Start the coroutine
launch {
Log.d(TAG, "[launch B] Begin")
delay(300)
Log.d(TAG, "[launch B] currThread: " + Thread.currentThread().name)
Log.d(TAG, "[launch B] end")}// End the coroutine
Log.d(TAG, "[GlobalScope] end ")}// The result is as follows:
// [GlobalScope] start
// [GlobalScope] currThread: DefaultDispatcher-worker-1
// [launch A] Begin
// [launch B] Begin
// [Coroutine] end
// [launch B] currThread: DefaultDispatcher-worker-1
// [launch B] end
// [launch A] currThread: DefaultDispatcher-worker-1
// [launch A] end
Copy the code
From the above results, it can be seen that when Launch A is suspended, the corresponding thread defaultDispatcher-worker-1 starts to execute tasks related to launch B. The delay() method does not block its corresponding thread of execution.
CoroutineScope usage description
GlobalScope is a singleton that has the same lifecycle as an Android application and is not associated with Android lifecycle components (activities, Services, etc.). The claim cycle needs to be managed by developers themselves. The proposed coroutine usage was not mentioned before. This section gives examples of the corresponding code usage:
CoroutineScope use examples:
Implement a CoroutineScope of your own via CoroutineScope, launch a coroutine, and cancel all ongoing tasks under that scope by calling scope.cancel().
// ------------ Example -----------
// CoroutineScope performs an asynchronous network task and returns the result to update the UI
//
class CoroutineScope01Activity : AppCompatActivity() {
/ / Job object
lateinit var scope: CoroutineScope
// The Activity's onCreate method
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Create CoroutineScope (to manage all Ctrips in CoroutineScope)
scope = CoroutineScope(Job() + Dispatchers.Main)
// Get network data and update UI
asyncCoroutine();
}
override fun onDestroy(a) {
super.onDestroy()
Cancel all coroutines managed by the Scope when the Activity is destroyed.
scope.cancel()
}
/** * CoroutineScope uses */
private fun asyncCoroutine(a) {
// CoroutineScope launches
scope.launch(Dispatchers.Main) {
// TODO executes the main thread // main thread
// The first asynchronous network request
val taobaoData = async(Dispatchers.IO) { // IO thread
// TODO IO thread network request
// Http synchronous network request with a String return value
HttpAgent.get_Sync(
"https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=18701636688".null.null,
String::class.java
)
}
// The second asynchronous network request
val baiduData = async(Dispatchers.IO) { // IO thread
// TODO IO thread network request
// Http synchronous network request with a String return value
HttpAgent.get_Sync(
"https://www.baifubao.com/callback?cmd=1059&callback=phone&phone=18701636688".null.null,
String::class.java
)
}
// After both results are returned
val resultData: String = (taobaoData.await() + baiduData.await())
/ / display the UItextView? .text = resultData// main thread}}}Copy the code
Activity implements the CoroutineScope interface
// ------------ Example -----------
// CoroutineScope performs an asynchronous network task and returns the result to update the UI
//
// Activity implements the CoroutineScope interface
class CoroutineScopeActivity : AppCompatActivity(), CoroutineScope {
/ / Job object
lateinit var job: Job;
// Override properties in the CoroutineScope interface
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
// The Activity's onCreate method
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.d(TAG, "---onCreate---")
// Create a Job (to manage all ctrips in CoroutineScope)
job = Job()
// Get network data and update UI
asyncCoroutine();
}
override fun onDestroy(a) {
super.onDestroy()
// Cancel the Scope managed job when the Activity is destroyed.
// All child coroutines created within this Scope are automatically cancelled.
job.cancel()
}
/** * CoroutineScope uses */
private fun asyncCoroutine(a) {
// CoroutineScope launches
job = launch(Dispatchers.Main) {
// TODO executes the main thread // main thread
// The first asynchronous network request
val taobaoData = async(Dispatchers.IO) { // IO thread
// TODO IO thread network request
// Http synchronous network request with a String return value
HttpAgent.get_Sync(
"https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=18701636688".null.null,
String::class.java
)
}
// The second asynchronous network request
val baiduData = async(Dispatchers.IO) { // IO thread
// TODO IO thread network request
// Http synchronous network request with a String return value
HttpAgent.get_Sync(
"https://www.baifubao.com/callback?cmd=1059&callback=phone&phone=18701636688".null.null,
String::class.java
)
}
// After both results are returned
val resultData: String = (taobaoData.await() + baiduData.await())
/ / display the UItextView01? .text = resultData// main thread}}}Copy the code
Download the source code
The source code download address is as follows: download.csdn.net/download/ai…
reference
Developer kotlin coroutines: developer. The android. Google. Cn/kotlin/coro…
Kotlin CoroutineScope: blog.chengyunfeng.com/?p=1086