coroutineScope start first than launch - kotlin

I'm studying coroutine,
and writing some examples, I found some weird things.
even if I write the launch build first,
it start late than coroutineScope.
I understand coroutineScope has a suspending point.
Is there any one who explain this?
below is my code
import kotlinx.coroutines.*
fun main() = runBlocking {
launch {
println("Start")
}
coroutineScope {
launch {
delay(1000)
println("World!")
}
println("Hello")
}
println("Done")
/*
expected
Start
Hello
World!
Done
result
Hello
Start
World!
Done
*/
}

launch block isn't executed immediately. It is sort of scheduled for asynchronous execution and the function returns immediately. That's why "Start" is not printed immediately and the control moves inside the coroutineScope. You can verify this with a simple example like:
launch {
println("Start")
}
println("End")
Here you will see that End is printed before Start

Related

Kotlin coroutine with runBlocking infinite loop

I found this snippet of code for an interesting case of an infinite loop (it's not a deadlock as one thread/coroutine keeps progressing) with Kotlin coroutines, but I can't seem to wrap my head around why removing the first yield() solves the issue?
Tried debugging it and it seems that while (job.isActive) yield() just schedules itself to run over and over, instead of scheduling job coroutine which I would be expecting.
Can someone explain why this code doesn't work, and why removing the first yield()fixes it?
#Test
fun testDeadlock() = runBlocking {
val job = launch {
runBlocking {
println("1")
}
println("2")
}
yield() // Comment yield and test starts to pass
runBlocking {
println("3")
while (job.isActive) yield()
}
}

Unable to create local variable inside coroutine

I'm new to Kotlin coroutines topic and there is one issue, which totally blocks me from using them. I have the following code to run with coroutines:
runBlocking {
for (i in 0 until args[1].toInt()) {
GlobalScope.launch {
OuterObject().run()
}
}
And my OuterObject class has the following code in run() method:
override fun run() {
...
logger.info(){ "Checkpoint 0" }
var innerObject: InnerObject = InnerObject(some_parameter = 1)
logger.info(){ "Checkpoint 1" }
...
}
All the coroutines got started from the loop but reach only "Checkpoint 0". There are no log messages or any other actions after innerObject creation attempt.
The first thing I tried is to create another object, but it seems like the issue is general and does not depend on object's class. I've tried with DateTime(), Gson() and some others - each time coroutines stop at this point. I've also tried to add exception handled to the coroutine but there is no exception catched - the coroutine just silently stops.
What is the reason behind this and how can I avoid it?
Version of kotlinx-coroutines-core: 1.2.2
UPDATE 1:
I've checked a primitive type assignment and it works. Both "Checkpoint 0" and "Checkpoint 1" appear in console logs. The issue is only with complex types.
override fun run() {
...
logger.info(){ "Checkpoint 0" }
var test = 1
logger.info(){ "Checkpoint 1" }
...
}
UPDATE 2:
#gladed and #Sam, you are right. The article of #roman-elizarov also helped me out: The reason to avoid GlobalScope. It was wrong to call "launch" from GlobalScope - it is not related to the runBlocking scope.
I've modified my code in the following way:
runBlocking {(0 until args[1].toInt()).forEach {
launch(Dispatchers.Default) {
OuterObject().run()
}
}
I got some further issues with running the code this way but they were due to not optimal concurrency.
launch() starts a new coroutine. But you're not waiting for it to complete. Instead, consider:
runBlocking {
(0 until args[1].toInt()).forEach {
launch {
OuterObject().run()
}
}
}
This way, runBlocking won't return until all the launched jobs are complete. (Credit to #Sam on removing GlobalScope.)

Kotlin coroutines - how to run in background and use result in the caller thread?

The main idea is to have non-suspend function runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit) which run some work asynchronously in background (another thread) and after work is done - run callback in the caller thread (thread that launched runInBackgroundAndUseInCallerThread).
Below I wrote an example code, but I'm not sure how correct it is and whether it is possible at all. With the println("1/2/3/...") I marked the desired call order.
getDispatcherFromCurrentThread - if is possible to implement this function, then solution can be used, but I don't know how to implement it and is it right to do it like that at all.
Therefore, please do not consider it as the only solution.
import kotlinx.coroutines.*
import kotlin.concurrent.thread
fun main() {
println("1")
runInBackgroundAndUseInCallerThread {
println("4")
println("Hello ${it.someField} from ${Thread.currentThread().name}") // should be "Hello TestField from main"
}
println("2")
thread(name = "Second thread") {
runInBackgroundAndUseInCallerThread {
println("5")
println("Hello ${it.someField} from ${Thread.currentThread().name}") // should be "Hello TestField from Second thread"
}
}
println("3")
Thread.sleep(3000)
println("6")
}
fun runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit) {
val dispatcherFromCallerThread: CoroutineDispatcher = getDispatcherFromCurrentThread()
CoroutineScope(Dispatchers.IO).launch {
val result: SomeModel = getModelResult()
launch(dispatcherFromCallerThread) { callback(result) }
}
}
data class SomeModel(val someField: String)
suspend fun getModelResult(): SomeModel {
delay(1000)
return SomeModel("TestField")
}
fun getDispatcherFromCurrentThread(): CoroutineDispatcher {
// TODO: Create dispatcher from current thread... How to do that?
}
Unless the thread is designed to work as a dispatcher there isn't a universal way to make it do so.
The only way which comes to mind is the fact that runBlocking is re-entrant and will create an event-loop in the existing thread, however it will block all non-coroutine code from executing on that thread until it completes.
This ends up looking like:
fun runInBackgroundAndUseInCallerThread(callback: (SomeModel) -> Unit) {
callback(runBlocking(Dispatchers.IO) {
getModelResult()
})
}
dispatcher really is a coroutineContext and it is meaningful when used inside a scope
thus if you want pass dispatcher of parent scope to child scope you can do it.
GlobalScope.launch {
val dispatcher = this.coroutineContext
CoroutineScope(dispatcher).launch {
}
}
therefor getDispatcherFromCurrentThread should be like this.
fun getDispatcherFromCurrentThread(scope: CoroutineScope): CoroutineContext {
return scope.coroutineContext
}
and
GlobalScope.launch {
val dispatcher = getDispatcherFromCurrentThread(this)
CoroutineScope(dispatcher).launch {
}
}
which run some work asynchronously in background (another thread) and after work is done - run callback in the caller thread
First try to answer this question: what is the calling thread supposed to do while the background work is in progress?
Clearly it can't go on to the next line of your code, which is supposed to run after finishing the background work.
You also don't want it to block and wait.
What code should it run, then?
And the only reasonable answer is as follows: the calling thread should, at its topmost level of execution (entry-point function), run an infinite event loop. The code in your question should be inside an event handler submitted to the event loop. At the point you want to wait for the background work, the handler must return so the thread can go on handling other events, and you must have another handler ready to submit when the background work is done. This second handler, corresponding to your callback, is called the continuation and Kotlin provides it automatically. You don't in fact need your own callback.
However, now the most sensitive issue arises: how will you submit the continuation to the event loop? This is not something you can abstract over, you must use some API specific to the event loop in question.
And this is why Kotlin has the notion of a Dispatcher. It captures the case-specific concern of dispatching continuations to the desired thread. You seem to want to solve it without the need to write a dispatcher dedicated to each specific event loop, and unfortunately this is impossible.

Why is Kotlin ignoring the delay(timeMillis: Long) function

The context
Following the Kotlin Coroutines basics guide at this point
using this code
fun coroutinesAreLightWeight()
{
runBlocking {
repeat(100_000) {
launch {
delay(1000L)
print("$it, ")
}
}
}
}
Issue
When I run the program on my computer it prints out all the digits in one go instead of waiting for 1 second to elapse before printing the next digit. This behaviour is the same when running the exact code as seen in the kotlin guide. It seems like the delay() function is being ignored
At first this block of code worked fine but then it stopped working as intended. I am using IntelliJ 2019.2.1 with kotlin version 1.3.50 and I have tried restarting the program but that didn't solve my problem.
Here is how the whole class looks like
class CoroutinesBasics
{
fun ...
fun ...
fun coroutinesAreLightWeight()
{
runBlocking {
repeat(100_000) {
launch {
delay(1000L)
print("$it, ")
}
}
}
}
}
and the coroutinesAreLightWeight() function is called like this
fun main()
{
CoroutineBasics().apply{
....
....
coroutinesAreLightWeight()
}
}
Can anyone point me to what is going on? Is this a Kotlin bug?
Kotlin dependencies
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
I'll take another angle to answer this.
The example is given in a specific context. Namely, "coroutines are not like threads". The goal of the example is not to demonstrate how to print numbers with delays, but to demonstrate that coroutines, unlike threads, can be launched in thousands simultaneously. And that's exactly what this code is doing. It submits them all, then executes them all.
You may ask then, why they are all sequential? Shouldn't they run concurrently?
For that, let's print the thread name:
repeat(100_000) {
launch {
delay(100L)
println("$it, ${Thread.currentThread().name}")
}
}
You'll quickly see the reason: 99999, main
Since you're using runBlocking, all your coroutines are executed by a single thread.
We can change it, though:
runBlocking {
repeat(100_000) {
launch(Dispatchers.Default) {
delay(100L)
println("$it, ${Thread.currentThread().name}")
}
}
}
By using Dispatchers.Default, we're running our coroutines on a default thread pool. And then the results become much less predictable:
98483, DefaultDispatcher-worker-6
99898, DefaultDispatcher-worker-5
99855, DefaultDispatcher-worker-1
99706, DefaultDispatcher-worker-2
The default thread pool starts with 2 threads, and goes up to number of CPU cores by default. You can look at createDefaultDispatcher() for the actual implementation.
Regarding Thread.sleep(), you should know a few things:
Never use Thread.sleep() inside coroutine
Never use Thread.sleep() inside coroutine
IntelliJ will even warn you to never use Thread.sleep() inside coroutine
Let's look at the following example to understand why:
repeat(100_000) {
launch {
Thread.sleep(100)
println("$it, ${Thread.currentThread().name}")
}
}
You may assume what you're saying is "don't do anything in this block for 100ms".
But what you're actually saying is "don't do literally anything for 100ms".
Since launch will execute on context it got from runBlocking, and runBlocking is a single threaded context, you block executions of all coroutines.
This is the intended behavior as far as I know because coroutines are working simultaneously, so your code will only wait for 1 second for all coroutines that are currently working.
A good talk that I recommend about the coroutines is:
KotlinConf 2017 - Introduction to Coroutines by Roman Elizarov
And it has the exact same example in the slides :)
if you want them to wait you should move the repeat to outside the 'runBlocking'

The example of the coroutine from documentation does not work

I started to learn coroutine and have tried run the code from example structured-concurrency. But I got another result. If set delay(1000L) "Hellow, " only was printed and Process finished with exit code -1073741819 (0xC0000005). But if I set delay(100L) I get "Hello,World!". Why launch{} block not launch?
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
launch { // launch a new coroutine in the scope of runBlocking
delay(100L)
println("World!")
}
println("Hello,")
}
screen 1
screen 2
Okey, I disabled the program "Punto switcher" and now all work correctly.