Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin: Coroutines scope vs Coroutine context

Can anyone explain the difference between them? I think scope provides a reference(e.g. Job) to cancel them and context provides a reference to underlying thread. Is that so?

like image 613
Jose Avatar asked Jan 29 '19 08:01

Jose


People also ask

What is coroutine scope and context?

a coroutine must run in a scope. it is a way to keep track of all coroutines that run in it. all (cooperative) coroutines can be cancelled via their scope. scopes get uncaught exceptions. they are a way to bind coroutines to an application specific lifecycle (e.g. viewModelScope in Android) to avoid leaking.

What is coroutines scope in Kotlin?

Kotlin coroutines provide an API that enables you to write asynchronous code. With Kotlin coroutines, you can define a CoroutineScope , which helps you to manage when your coroutines should run. Each asynchronous operation runs within a particular scope.

How do you get coroutine context in Kotlin?

coroutines . To find a CoroutineName , we use just CoroutineName . This is not a type or a class: it is a companion object. It is a feature of Kotlin that a name of a class used by itself acts as a reference to its companion object, so ctx[CoroutineName] is just a shortcut to ctx[CoroutineName.

What is scope coroutines Android?

Scope in Kotlin's coroutines can be defined as the restrictions within which the Kotlin coroutines are being executed. Scopes help to predict the lifecycle of the coroutines.


2 Answers

They are indeed closely related. You might say that CoroutineScope formalizes the way the CoroutineContext is inherited.

CoroutineScope has no data on its own, it just holds a CoroutineContext. Its key role is as the implicit receiver of the block you pass to launch, async etc.

See this example:

runBlocking {
    val scope0 = this
    // scope0 is the top-level coroutine scope.
    scope0.launch {
        val scope1 = this
        // scope1 inherits its context from scope0. It replaces the Job field
        // with its own job, which is a child of the job in scope0.
        // It retains the Dispatcher field so the launched coroutine uses
        // the dispatcher created by runBlocking.
        scope1.launch {
            val scope2 = this
            // scope2 inherits from scope1
        }
    }
}

You can see how the CoroutineScope mediates the inheritance of coroutine contexts. If you cancel the job in scope1, this will propagate to scope2 and will cancel the launched job as well.

Note the key syntactical feature: I explicitly wrote scope0.launch, but had I written just launch, it would implicitly mean exactly the same thing. This is how CoroutineScope helps to "automatically" propagate the scope.

like image 114
Marko Topolnik Avatar answered Oct 22 '22 09:10

Marko Topolnik


Yes, in principle you are right, here more details.

Scope

  • a coroutine must run in a scope
  • it is a way to keep track of all coroutines that run in it
  • all (cooperative) coroutines can be cancelled via their scope
  • scopes get uncaught exceptions
  • they are a way to bind coroutines to an application specific lifecycle (e.g. viewModelScope in Android) to avoid leaking

Context

The context determines on which thread the coroutines will run. There are four options:

  • Dispatchers.Default - for CPU intense work (e.g. sorting a big list)
  • Dispatchers.Main - what this will be depends on what you've added to your programs runtime dependencies (e.g. kotlinx-coroutines-android, for the UI thread in Android)
  • Dispatchers.Unconfined - runs coroutines unconfined on no specific thread
  • Dispatchers.IO - for heavy IO work (e.g. long-running database queries)

The following example brings both scope and context together. It creates a new scope in which the coroutines will run (if not changed) on a thread designated for IO work and cancels them via their scope.

val scope = CoroutineScope(context = Dispatchers.IO) 
val job = scope.launch {
    val result = suspendFunc1()
    suspendFunc2(result)
}
// ...
scope.cancel() // suspendFunc1() and suspendFunc2() will be cancelled
like image 44
Willi Mentzel Avatar answered Oct 22 '22 08:10

Willi Mentzel