Coroutine basics
A coroutine is an instance of suspendable computation. It is conceptually similar to a thread. However, a coroutine is not bound to any particular thread. It may suspend its execution in one thread and resume in another one.
Coroutines can be thought of as light-weight threads, but there is a number of important differences that make their real-life usage very different from threads.
Coroutine Builders
Coroutine builders are a way of creating coroutines. Since they are not suspending themselves, they can be called from non-suspending code or any other piece of code. They act as a link between the suspending and non-suspending parts of our code.
launch
launch
Launches a new coroutine without blocking the current thread and returns a reference to the coroutine as a Job. The coroutine is cancelled when the resulting job is cancelled.
1 2 3 4 5 6 7 8 |
|
The launch function is an extension function on the interface CoroutineScope
. This is a part of an important mechanism called structured concurrency, with the purpose of building a relationship between parent coroutine and child coroutine. Coroutines are launched in coroutine builders and are bound by a coroutine scope. A lazy way to launch a coroutine would be to use the GlobalScope
. This means that the coroutine would be running for as long as the application is running and, if there is no important reason to do this, I believe that it’s a way to wrongly use resources.
1 2 3 4 5 |
|
CoroutineContext
is a persistent dataset of contextual information about the current coroutine
CoroutineStart
is the mode in which you can start a coroutine.
- DEFAULT: Immediately schedules a coroutine for execution according to its context.
- LAZY: Starts the coroutine lazily, only when it is needed.
- ATOMIC: Same as DEFAULT but cannot be cancelled before it starts.
- UNDISPATCHED: Runs the coroutine until its first suspension point.
runblocking
runBlocking
is a coroutine builder that blocks the current thread until all tasks of the coroutine it creates, finish
1 2 3 4 5 6 7 |
|
async
async
is a coroutine builder which returns some value to the caller. async can be used to perform an asynchronous task which returns a value
await
is a suspending function that is called upon the async builder to fetch the value of the Deferred object that is returned.
1 2 3 4 5 6 7 |
|
withContext
Calls the specified suspending block with a given coroutine context, suspends until it completes, and returns the result.
Structured Concurrency
If a coroutine is started on GlobalScope
, the program will not wait for it. For example:
1 2 3 4 5 6 7 8 9 |
|
Everything changes if we get rid of the GlobalScope
here. runBlocking
creates a CoroutineScope
and provides it as its lambda expression receiver. Thus we can call this.launch
or simply launch
. As a result, launch
becomes a child of runBlocking
. As parents might recognize, parental responsibility is to wait for all its children, so runBlocking
will suspend until all its children are finished.
Scope builder
CoroutineScope
is an interface that has a single abstract property called coroutineContext
.
1 2 3 |
|
Whenever a new coroutine scope is created, a new job gets created and gets associated with it. Every coroutine created using this scope becomes the child of this job.
GlobalScope
This is a singleton and not associated with any Job. This launches top-level coroutines and highly discouraged to use because if you launch coroutines in the global scope, you lose all the benefits you get from structured concurrency.
Reference: https://elizarov.medium.com/the-reason-to-avoid-globalscope-835337445abc
MainScope
This is useful for UI components, it creates SupervisorJob
and all the coroutines created with this scope runs on the Main thread.
CoroutineScope(ctx)
This creates a coroutine scope from provided coroutine context and makes sure that a job is associated with this scope.
1 |
|
coroutineScope
Kotlin avoid thread blocking functions inside coroutine so due to this the use of runBlocking
is discouraged from inside coroutines ans allow suspending operation instead of this. The suspending function is equivalent of runBlocking
is the coroutineScope
builder.
CoroutineScope
suspends the currently working coroutine until all it’s child coroutines have finished their execution.
1 2 3 4 5 6 7 8 9 10 11 |
|