SoFunction
Updated on 2025-03-11

Detailed explanation of the coroutineScope function usage of kotlin coroutine

text

public suspend fun <R> coroutineScope(block: suspend CoroutineScope.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return suspendCoroutineUninterceptedOrReturn { uCont ->
        val coroutine = ScopeCoroutine(, uCont, true)
        (coroutine, block)
    }
}

It's asuspendFunction, creates a new coroutine scope and executes a specified code block within that scope, it does not start coroutines. The purpose of its existence is to perform parallel decomposition that conforms to structured concurrency (i.e. split long time-consuming tasks into multiple short time-consuming tasks that are concurrent, and wait for all concurrent tasks to complete before returning).

coroutineScopeandrunBlockingThe difference isrunBlockingwill block the current thread, andcoroutineScopeThe coroutine that is located will be suspended until its internal tasks (including child coroutines) are completed, and it will not block the thread that is located.

coroutineScopeis a suspended function. After it is suspended, it will instead execute the previous child coroutine.

fun main() = runBlocking {
    launch {        //launch①       
        delay(1000)                 //Hang launch①        println("test2")
    }
    println("test1")
    coroutineScope {                //The first time the runBlocking is suspended until the internal logic is completed        launch {    //launch②
            delay(2000)             //Hang launch②            println("test3")
        }
        delay(5000)     //delay① //Suspend runBlocking for the second time        println("test4")
    }
    println("test5")
}
//test1
//test2
//test3
//test4
//test5

Code Analysis

  • runBlockingexistmainThe thread creates and starts a blocking coroutine;
  • createlaunch①As a child coroutine, it takes some time to create a coroutine, and the creation of a coroutine is done by a specific thread, not a main thread. Therefore, subsequent code will be executed in parallel during the creation of the coroutine. thereforetest1Being output.
  • Execute tocoroutineScopeWhen function,runBlockingPending until the internal logic execution is complete.
  • Then createlaunch②Coroutine, execute subsequent code during creation:delay①Continue to hangrunBlocking5s (the suspend function is called in the suspend function).
  • wait untillaunch①When the creation is complete, hang it for 1s.launch②When the creation is finished, hang it for 2 seconds.
  • at this timerunBlocking、launch①、launch②All are suspended.
  • Wait until 1slaunch①Recover, outputtest2;After 2 secondslaunch②Recovered, outputtest3;After 5srunBlockingThe second hang is restored, the output istest4
  • at this timecoroutineScopeThe logic in the process has been completed and restoredrunBlockingThe first time hangs,test5Being output.

This is difficult to understand, and the following cases are a little easier:

fun main() = runBlocking {
    launch {
        println("test3")
    }
    println("test1")
    coroutineScope {    //Hang runBlocking until the internal logic completes        println("test2")
        delay(1000)     //Hang runBlocking5s        println("test4")
    }
    println("test5")    //The suspended function coroutineScope must be executed before it is executed}
//test1
//test2
//test3
//test4
//test5

And ifcoroutineScopeChange the function todelayFunctions, it will be easier to understand because they are all suspended functions.

fun main() = runBlocking {
    launch {
        delay(1000)
        println("test2")
    }
    println("test1")
    delay(2000)     //Hang the runBlocking coroutine 2s    println("test3")
}
//test1
//test2
//test3

coroutineScopeOften used to split a long and time-consuming task into multiple subtasks, so that these subtasks can be executed in parallel.

suspend fun showSomeData() = coroutineScope {
    val data1 = async {         //Subtask 1        delay(2000)
        100
    }
    val data2 = async {         //Subtask 2        delay(3000)
        20
    }
    withContext() {      //Merge the results and return        delay(3000)
        val random = Random(10)
        () + () + (100)
    }
}

coroutineScopeThere are the following semantics:

  • Perform internal tasks in paralleldata1data2withContext
  • If other tasks (random)throw an exception,data1anddata2Both tasks will be cancelled
  • ifshowSomeData()Cancel, internaldata1data2withContextWill be cancelled
  • ifdata1data2fail,withContextCanceled.

The above is the detailed explanation of the coroutineScope function of the kotlin coroutine coroutine. For more information about the coroutineScope function of the kotlin coroutine coroutine, please pay attention to my other related articles!