https://kotlinlang.org logo
#coroutines
Title
# coroutines
a

Abhi

03/02/2024, 1:51 PM
Bit confused with thus illustration here, https://elizarov.medium.com/coroutine-context-and-scope-c8b255d59055 My confusions is with Parent and Child scope. Is he calling it Child scope, just because the scope in which the child coroutine runs has a context made of Parent Context + new Child Job? For example, all the 3 coroutines launched here, belong to the same coroutine scope? or new child scopes are created for each launch?
Copy code
fun main() = runBlocking<Unit> {
    launch { 
      launch { 
        launch { 
          delay(1000)
        }
        delay(1000)
      }   
      delay(1000)
    }
}
j

Jeff Lockhart

03/02/2024, 5:04 PM
All those
launch
calls are being called from the same
CoroutineScope
receiver from
runBlocking
. Each call to
launch
creates a new coroutine with its own
Job
, which is returned by the call. That
Job
is a child of the parent
runBlocking
scope's
Job
. If you were to include additional context in the
launch
calls, e.g.
launch(Dispatchers.Main + CoroutineName("coroutine-A")) { ...
, that context would be merged with the parent scope's context from
runBlocking
(by default here, just
EmptyCoroutineContext
), which would be the coroutine's parent context. That parent context plus the child
Job
is equal to the child context, which makes up the child scope. It's the
Job
that defines when a
CoroutineScope
is cancelled. And that
Job
potentially has a parent/child relationship with other `Job`s in order to propagate cancellation. A
SupervisorJob
is unique in that it does not propagate its cancellation. For this reason, a top-level
CoroutineScope
is often defined with a
SupervisorJob
.
So taking your example code and adding some `CoroutineContext`s to it, you can see how the coroutine contexts and child scopes are composed:
Copy code
fun main() = runBlocking<Unit>(CoroutineName("foo")) {
    // Dispatchers.Main + CoroutineName("foo") + job1
    val job1 = launch(Dispatchers.Main) {
        // CoroutineName("bar") + job2
        val job2 = launch(CoroutineName("bar")) {
            // CoroutineName("bar") + job3
            val job3 = launch {
                delay(1000)
            }
            delay(1000)
        }
        delay(1000)
    }
}
a

Abhi

03/03/2024, 10:33 AM
for job3 = launch { }, it would be // CoroutineName("bar") + job3?
Copy code
fun main(): Unit = runBlocking {
    launch(CoroutineName("foo")) {
        launch(CoroutineName("bar")) {
            launch {
                println(coroutineContext[CoroutineName])
            }
        }
    }
}
Output: CoroutineName(bar)
thanks for the explaination @Jeff Lockhart, appreciate it. Helped me improve my understanding of coroutines better
j

Jeff Lockhart

03/03/2024, 3:03 PM
for job3 = launch { }, it would be // CoroutineName("bar") + job3?
Ah, yes. This is a good point because it shows how the parent context comes from the coroutine being launched from.
2 Views