What is Thread?
A thread controls what executes in which order, to understand threads better
first lets understand a few things.
The program / set of code that
we write becomes a process when it is loaded into the memory. Now this
process can be executed on a single processor or multiple processors.
Each
process has its own program counter, registers , signals etc.
This
helps it in keeping track of the program execution i.e which line of
instruction or code is currently being executed.
So A thread is a
sequence of such instructions that can run independently, meaning we can have
multiple threads in a program that will run and perform its operations without
interrupting the other threads.
Since a process can have multiple threads and the memory of threads
inside the same process is shared , every thread within the same process
has access to that memory space.
Threads contain only thread specific
data such as stack, local variables, function arguments etc, rest all the
data is shared across the threads, this helps in scheduling threads
individually.To give brief definition Threads are imperative programs that
run concurrently and share a memory space. They can access each others’
variables.
What is Coroutine in kotlin?
Coroutines you can say it as a light weight thread, but don't confuse
coroutines with threads, coroutines are very much different from threads.
Thus coroutines are similar to Threads but differ in many ways.
When we write functions in kotlin, java or any other programming languages, usually until the inner function finishes the work the outer function has to wait to get the control, so if the task is to do some IO operation or network call the thread on which the outer function is executing gets blocked due to this.
If F1 is dependent on the outcome of F2 then this wait is acceptable but what if F1 is independent and doesn't really care about the outcome? But still it has to wait till the IO is complete thus blocking the F1 execution and the thread on which it is running.
Similarly, say we have 2 tasks t1 and t2 that are called in main method are sequential but it can be done concurrently . So that the main thread is not blocked due to this.
fun main(args: Array<String>) {
println("Main started.")
task1()
task2()
println("Main ended.")
}
fun task1(){
println("task 1 started.")
// operation
println("task 1 ended.")
}
fun task2(){
println("task 2 started.")
//operation.
println("task 2 ended.")
}
Output:
Main started.
task 1 started.
task 1 ended.
task 2 started.
task 2 ended.
Main ended.
So you might say just use Thread then right.
So here coroutines can be used as coroutines are light weight.For example if you where to create 1 lakh coroutines and 1 lakh threads , the resource consumption of 1 lakh coroutines will be far more less than that of the Threads, whereas on other hand creating this many threads will simply through out of memory error or will not create this many threads in parallel there will be some delay in the thread creation to avoid concurrent thread running.
Thus Coroutines are much more useful when it comes to concurrent execution than threads.
Now lets take the same example above and try to run it concurrently using coroutines.
suspend fun task1(){
println("task 1 started.")
delay(3000)
println("task 1 ended.")
}
suspend fun task2(){
println("task 2 started.")
delay(4000)
println("task 2 ended.")
}
suspend fun f1(){
coroutineScope {
println("f1 started.")
launch {
task1()
}
launch {
task2()
}
println("f1 ended.")
}
}
fun main(args: Array<String>){
runBlocking {
println("Main started.")
f1()
println("Main ended.")
}
}
Ouput:
Main started.
f1 started.
f1 ended.
task 1 started.
task 2 started.
task 1 ended.
task 2 ended.
Main ended.
Explanation:
Say we have 2 tasks task1 and task2 that can be executed independently and let the function f1 continue its other work without waiting for these functions to finish , so we need to do this concurrent programming but instead of using threads we will use coroutine here.
We create a coroutineScope{} in the function f1 and launch 2 new coroutine inside it and let the task1 and task2 run on those 2 different coroutines separately.
the launch{} will create a separate coroutine and start the execution on the operations inside it.
As the coroutines are launched the last line of the coroutineScope gets executed and later on the child coroutines finishes its operations and gets completed.
We should note the to maintain the Structured concurrency, till all the child coroutines are finished the coroutineScope is not closed.
What is coroutineScope{} in Kotlin?
- As the name suggests it defines the scope of new coroutines.
- This function creates a new CoroutineScope within that context.
- The function waits till all the child coroutine are finished or cancelled in the scope i.e It creates a coroutine scope and does not complete until all launched children complete.
- If any child fails , the scope is failed and all other coroutines are cancelled.
- Every coroutine builder (like launch, async, etc.) is an extension on CoroutineScope and inherits its coroutineContext to automatically propagate all its elements and cancellation.
What is launch{} in kotlin coroutine?
- launch is a coroutine builder.
- It starts a new coroutine in parallel with the remaining portion of the code, which keeps running on its own.
- The coroutine that is launched in created without blocking the current thread.
- launch returns a Job that represents the coroutine. It is possible to wait until it completes by calling Job.join()
suspend fun f1(){
coroutineScope {
println("f1 started.")
launch {
task1()
}
launch {
task2()
}
println("f1 ended.")
}
}
What is async{} in kotlin coroutine?
- async is a coroutine builder similar to launch.
- It starts a new coroutine concurrently with the remaining portion of the code , which keeps running on its own.
- A new coroutine is created and a Deferred object is returned by async. Deferred is another term for a concept that is also called Promise or Future.
- It promises the result at a later time and stores a computation, delaying the moment you receive the final result.
- To get the result await() method is called on the deferred instance.
package coroutineTutorial
import kotlinx.coroutines.*
fun main() {
runBlocking {
f1()
}
}
suspend fun f1() {
coroutineScope {
println("coroutineScope line 1")
var result= async {
task1()
}
var result2= async {
task2()
}
println(result.await())
println(result2.await())
println("coroutineScope line last.")
}
println("f1 fun end.")
}
suspend fun task1(): String {
println("task 1 started.")
delay(5000)
return "KodeSrc!"
}
suspend fun task2(): String {
println("task 2 started.")
delay(3000)
return "Async KodeSrc!"
}
Output:
coroutineScope line 1
task 1 started.
task 2 started.
KodeSrc!
Async KodeSrc!
coroutineScope line last.
f1 fun end.
What is the difference between async and launch and When to use it?
- The main difference between async and launch is that launch is used when we don't expect a result from the execution and async is used when we expect a result from the function/ coroutine/ task.
- launch and async are declared as extensions to CoroutineScope, so an implicit or explicit receiver must always be passed when you call them.
runblocking{} and coroutineScope{} use and difference.
- Both runBlocking{} and coroutineScope{} are scope builders. They create scope for coroutines to execute.
- Coroutine builders like launch{}, async{} can only be executed inside any scope builder like runBlocking{} or coroutineScope{}.
- Both waits till all child coroutine finishes and then the scope is closed.
- But there is 1 major difference between runBlocking and coroutineScope. runBlocking is a normal method which blocks the thread on which it is running, whereas coroutineScope is a suspending function which suspends the coroutine and releases the thread on which it was running allowing that thread to perform other operatios.
fun main() {
runBlocking {
f1()
}
}
What is GlobalScope and GlobalScope.launch{}, GlobalScope.async{}?
- In general term a Scope is responsible for its child coroutines.
- A coroutines lifetime is attached to its scope and a scope can cancel its child coroutine if anything goes wrong.
- Scope builders like runBlocking{} and coroutineScope{} waits till all the child coroutine are completed and if any child coroutine fails or throws exception all other coroutines are cancelled.
- All coroutines are structurally binded to its scope.
- GlobalScope creates a top level independent coroutines.
- There is no structure that binds these coroutines to a smaller scope.
- Coroutines started from the global scope are all independent – their lifetime is limited only by the lifetime of the whole application.
- If anything goes wrong or there is a continues process going on the coroutines created by GlobalScope can keep on running and consume the resources which can cause memory issues.
- So it is advised not to use GlobalScope unless you are sure of its use case.
suspend fun main() {
println("Main start.")
globalScopeExample()
println("line after method call.")
delay(6000)
println("Main End.")
}
fun globalScopeExample(){
println("inside globalScopeExample")
GlobalScope.launch {
println("coroutine started in global scope.")
delay(3000)
println("task completed inside global scope.")
}
println("Ending line of globalScopeExample method.")
}
Output:
Main start.
inside globalScopeExample
Ending line of globalScopeExample method.
line after method call.
coroutine started in global scope.
task completed inside global scope.
Main End.
What is a suspend function in kotlin?
What is Coroutine Context and Dispatchers in Kotlin?
- The coroutine context is a set of variables , it holds the data that is needed by the coroutine to perform.
- The main elements of Coroutine Context are Jobs and Dispatcher.
- A coroutine that is launched inside of another coroutine takes on the context of the outer coroutine. When the parent coroutine is terminated, the child coroutine is also terminated.
What is Job in Coroutine Context?
- Job is basically a handler that runs in the background and is responsible for the launched coroutines handling.
- Cancellation, result receiving this things are handled by the Job.
What is Dispatcher in Coroutine Context?
- Dispatchers are very import for coroutines as it decides which coroutine runs on which thread.
- The Dispatcher can decide to let the coroutine run on new thread, assign it a thread pool or let it run unconfined way.
Different Dispatchers:
- Dispatchers.Default: It uses a shared thread pool on the JVM
- Dispatchers.IO : It is used to perform blocking IO operations to a shared thread pool.
- Dispatchers.Unconfined : It launches the coroutine on the thread on which the calling function was running, it doesn't change or create new thread.
Please Let me Know, If you have any doubts.
Please Let me Know, If you have any doubts.