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:

  • suspendKey words:

When ctrip is blocked, it is used to suspend the current coroutine and save all local variables.

  • withContextMethods:

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:

  • asyncMethods:

The async method starts a new coroutine;

  • awaitKey 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