Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 333 Vote(s) - 3.47 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Difference between a thread and a coroutine in Kotlin

#1
Is there a specific language implementation in Kotlin which differs from another language's implementation of coroutines?

- What does it mean that a coroutine is like a lightweight thread?
- What is the difference?
- Are Kotlin coroutines actually running in parallel (concurrently)?
- Even in a multi-core system, is there only one coroutine running at any given time?

Here I'm starting 100,000 coroutines. What happens behind this code?

for(i in 0..100000){
async(CommonPool){
// Run long-running operations
}
}




Reply

#2
Since I used coroutines only on JVM, I will talk about the JVM backend. There are also Kotlin Native and Kotlin JavaScript, but these backends for Kotlin are out of my scope.

So let's start with comparing Kotlin coroutines to other languages coroutines. Basically, you should know that there are two types of *coroutines*: stackless and stackful. Kotlin implements stackless coroutines - it means that coroutine doesn't have its own stack, and that limiting a little bit what coroutine can do. You can read a good explanation [here][1].

Examples:

- Stackless: C#, Scala, Kotlin
- Stackful: Quasar, Javaflow

> What does it mean that a coroutine is like a lightweight thread?

It means that coroutine in Kotlin doesn't have its own stack, it doesn't map on a native thread, it doesn't require context switching on a processor.

> What is the difference?

Thread - preemptively multitasking. ([usually][2]).
Coroutine - cooperatively multitasking.

Thread - managed by OS (usually).
Coroutine - managed by a user.

> Are Kotlin coroutines actually running in parallel (concurrently)?

It depends. You can run each coroutine in its own thread, or you can run all coroutines in one thread or some fixed thread pool.

More about how coroutines execute is [here][3].

> Even in a multi-core system, is there only one coroutine running at any given time?

No, see the previous answer.

> Here I'm starting 100,000 coroutines. What happens behind this code?

Actually, it depends. But assume that you write the following code:

fun main(args: Array<String>) {
for (i in 0..100000) {
async(CommonPool) {
delay(1000)
}
}
}

This code executes instantly.

Because we need to wait for results from `async` call.

So let's fix this:

fun main(args: Array<String>) = runBlocking {
for (i in 0..100000) {
val job = async(CommonPool) {
delay(1)
println(i)
}

job.join()
}
}

When you run this program, Kotlin will create 2 * 100000 instances of `Continuation`, which will take a few dozen MB of RAM, and in the console, you will see numbers from 1 to 100000.

So let’s rewrite this code in this way:

fun main(args: Array<String>) = runBlocking {

val job = async(CommonPool) {
for (i in 0..100000) {
delay(1)
println(i)
}
}

job.join()
}

What do we achieve now? Now we create only 100,001 instances of `Continuation`, and this is much better.

Each created Continuation will be dispatched and executed on CommonPool (which is a static instance of ForkJoinPool).

[1]:

[To see links please register here]

[2]:

[To see links please register here]

[3]:

[To see links please register here]



Reply

#3
> What does it mean that a coroutine is like a lightweight thread?

Coroutine, like a thread, represents a sequence of actions that are executed concurrently with other coroutines (threads).

> What is the difference?

A thread is directly linked to the native thread in the corresponding OS (operating system) and consumes a considerable amount of resources. In particular, it consumes a lot of memory for its stack. That is why you cannot just create 100k threads. You are likely to run out of memory. Switching between threads involves OS kernel dispatcher and it is a pretty expensive operation in terms of CPU cycles consumed.

A coroutine, on the other hand, is purely a user-level language abstraction. It does not tie any native resources and, in the simplest case, uses just one relatively small object in the JVM heap. That is why it is easy to create 100k coroutines. Switching between coroutines does not involve OS kernel at all. It can be as cheap as invoking a regular function.

> Are Kotlin coroutines actually running in parallel (concurrently)? Even in a multi-core system, is there only one coroutine running at any given time?

A coroutine can be either running or suspended. A suspended coroutine is not associated to any particular thread, but a running coroutine runs on some thread (using a thread is the only way to execute anything inside an OS process). Whether different coroutines all run on the same thread (a thus may use only a single CPU in a multicore system) or in different threads (and thus may use multiple CPUs) is purely in the hands of a programmer who is using coroutines.

In Kotlin, dispatching of coroutines is controlled via _coroutine context_. You can read more about then in the
[Guide to kotlinx.coroutines][1]

> Here I'm starting 100,000 coroutines. What happens behind this code?

Assuming that you are using `launch` function and `CommonPool` context from the `kotlinx.coroutines` project (which is open source) you can examine their source code here:

- `launch` is defined here

[To see links please register here]

- `CommonPool` is defined here

[To see links please register here]


The `launch` just creates new coroutine, while `CommonPool` dispatches coroutines to a `ForkJoinPool.commonPool()` which does use multiple threads and thus executes on multiple CPUs in this example.

The code that follows `launch` invocation in `{...}` is called a _suspending lambda_. What is it and how are suspending lambdas and functions implemented (compiled) as well as standard library functions and classes like `startCoroutines`, `suspendCoroutine` and `CoroutineContext` is explained in the corresponding [Kotlin coroutines design document][2].

[1]:

[To see links please register here]

"Guide to kotlinx.coroutines"
[2]:

[To see links please register here]

"Kotlin coroutines design document"




Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through