Kotlin not waiting for a coroutine to finish? - kotlin

I'm learning coroutines and am a little confused by something
import kotlinx.coroutines.*
#OptIn(DelicateCoroutinesApi::class)
fun main() {
println("[${Thread.currentThread().name}] In main thread")
GlobalScope.launch {
println("[${Thread.currentThread().name}] In coroutine")
repeat(4) {
println("$it")
}
}
}
When I run this code, the output is a little unpredictable, sometimes I get output from the couroutines, sometimes I don't..
could someone please explain what is causing this? Thank you!

I believe there are a few options, but the heart of the matter is the main thread believes your program is done, so it ends the program. You need to wait for the coroutine to complete. Try the below block. It waits for the coroutine to complete before proceeding:
val job = GlobalScope.launch {
println("[${Thread.currentThread().name}] In coroutine")
repeat(4) {
println("$it")
}
}
job.join()
more info can be found here, https://kotlinlang.org/docs/coroutines-basics.html#an-explicit-job

Related

How to understand Coroutine Process with Example in kotlin

I'm studying coroutine with docs and some examples.
testing some examples, I found that in same CoroutineScope it works sequentially.
For example
Below code is working sequentially.
fun main() = runBlocking {
coroutineScope {
launch {
delay(1000)
println("Start")
}
}
coroutineScope {
launch {
delay(2000)
println("World2")
}
launch {
delay(1000)
println("World1")
}
println("Hello")
}
println("Done")
}
/*
Start
Hello
World1
World2
Done
*/
But If I change above codes like this
fun main() = runBlocking {
launch {
delay(1000)
println("Start")
}
coroutineScope {
launch {
delay(2000)
println("World2")
}
launch {
delay(1000)
println("World1")
}
println("Hello")
}
println("Done")
}
/*
Hello
Start
World1
World2
Done
*/
Removing first CoroutineScope, the result sequence is changed.
In My Opinion, I think this is a problem of job state, but not sure.
Is there anyone who can clarify this issue?
coroutineScope suspends until all its children coroutines have finished their execution. In your first case, the coroutineScope waits until the launch completes and prints Start, that's why you see Start as the first output on console.
In the second part, you removed the coroutineScope, so now it just launches a new coroutine and moves to the next step (launch doesn't suspend). Then in the coroutineScope you launch two other coroutines (using launch) and print Hello. That's why the Hello gets printed first. All other print statements are waiting for the delay to finish.
After 1 second, the first launch completes and prints Start followed by World1 and World2. Now when this coroutineScope finishes, the program control moves to the final print statement and prints Done.

testing the diff between coroutin and thread, I can't get the OOM error when using thread in kotlin

I'm studying coroutine now, and testing some difference with thread.
stydying with the kotlin docs, I copied some test code and changed the code for testing thread.
the docs said
https://kotlinlang.org/docs/coroutines-basics.html#coroutines-are-light-weight
If you write the same program using threads (remove runBlocking, replace launch with thread, and replace delay with Thread.sleep), it will likely consume too much memory and throw an out-of-memory error.
but I can't get anything about the error.
Is there any problem in my code?
fun main() = runBlocking {
repeat(1000000) {
thread {
sleep(5000L)
print(".")
}
}
}
The main point in the docs is that coroutines are more light-weight than threads. But whether an out-of-memory error is thrown or not depends on the resources of your JVM. There may be enough memory to start all the 100k threads.
You can try to increase the number of threads until you get an OOM error and then try to launch the same number of coroutines, and that should work. It's easy to reproduce in the kotlin playground as it has limited resources. I've tested this piece of code there and it throws an OOM for threads but doesn't for coroutines .
import java.lang.Thread.sleep
import kotlin.concurrent.thread
import kotlinx.coroutines.*
fun main() {
try {
repeat(10_000) { // launch a lot of threads
thread {
sleep(5000L)
print(".")
}
}
} catch (e: java.lang.OutOfMemoryError) {
println("Thread creation failed: " + e)
}
try {
runBlocking {
repeat(10_000) { // launch a lot of coroutines
launch {
delay(5000L)
print(".")
}
}
}
} catch (e: java.lang.OutOfMemoryError) {
println("Coroutine creation failed: " + e)
}
}
Your quote also said to remove the runBlocking. The following code did only timeout on my machine, limited to 30s.
fun main() = repeat(1000000) {
thread {
Thread.sleep(5000L)
print(".")
}
}
main()

Differences between two coroutine launch in kotlin

What's the difference between CoroutineScope(dispatchers).launch{} and coroutineScope{ launch{}}?
Say I have the code below:
(you can go to Kotlin playground to run this snippet https://pl.kotl.in/U4eDY4uJt)
suspend fun perform(invokeAfterDelay: suspend () -> Unit) {
// not printing
CoroutineScope(Dispatchers.Default).launch {
delay(1000)
invokeAfterDelay()
}
// will print
coroutineScope {
launch {
delay(1000)
invokeAfterDelay()
}
}
}
fun printSomething() {
println("Counter")
}
fun main() {
runBlocking {
perform {
printSomething()
}
}
}
And as the comment stated, when using CoroutineScope().launch it won't invoke the print, however when using the other way, the code behaves as intended.
What's the difference?
Thanks.
Further question
New findings.
if I leave the perform function like this (without commenting out one of the coroutines)
suspend fun perform(invokeAfterDelay: suspend () -> Unit) {
CoroutineScope(Dispatchers.Default).launch {
delay(1000)
invokeAfterDelay()
}
coroutineScope {
launch {
delay(1000)
invokeAfterDelay()
}
}
}
then both of these coroutines will be executed 🤔Why?
CoroutineScope().launch {} and coroutineScope { launch{} } have almost nothing in common. The former just sets up an ad-hoc scope for launch to run against, completing immediately, and the latter is a suspendable function that ensures that all coroutines launched within it complete before it returns.
The snippet under your "Further question" is identical to the original one except for the deleted comments.
Whether or not the first coroutine prints anything is up to non-deterministic behavior: while perform is spending time within coroutineScope, awaiting for the completion of the inner launched coroutine, the first one may or may not complete itself. They have the same delay.

How to execute a blocking coroutine call in kotlin and specify the thread

Is it possible to execute a blocking coroutine call (one that returns a value) while also providing the thread to execute the call on (I don't want to use the main thread, which is the default)?
I suppose you are looking for async(context):
import kotlinx.coroutines.*
fun someCalc(): Int {
println(Thread.currentThread().name) // Prints different thread
Thread.sleep(500L)
return 42
}
fun main() {
val result = runBlocking {
val deferred = async(Dispatchers.Default) {
someCalc()
}
deferred.await()
}
println(result)
}
You can also use newSingleThreadContext() to create a context confined to a single thread and use it instead of Dispatchers.Default
EDIT: As #Rene said, there is a better solution:
val result = runBlocking {
withContext(Dispatchers.Default) {
someCalc()
}
}
If you just have a thread that's already running, and you have no control over the code it runs, then there is nothing you can do about it. The thread must be running a top-level event loop so you can inject the code to run from the outside.
If, by any chance, you have this kind of control, or you can decide which Runnable the thread will run to begin with, here's some pretty hacky code that manages to set up an event loop and submit a coroutine to it:
val myContextFuture = CompletableFuture<CoroutineContext>()
thread(name = "my-thread") {
runBlocking {
myContextFuture.complete(coroutineContext)
coroutineContext[Job]!!.join()
}
}
val myContext = myContextFuture.get()
Here's how you would run a coroutine on myContext:
val result = withContext(myContext) {
println("Running on thread ${currentThread().name}")
3
}
println("Result of the coroutine: $result")
I wouldn't recommend using this kind of code in production.

Kotlin Coroutines - How to block to await/join all jobs?

I am new to Kotlin/Coroutines, so hopefully I am just missing something/don't fully understand how to structure my code for the problem I am trying to solve.
Essentially, I am taking a list of strings, and for each item in the list I want to send it to another method to do work (make a network call and return data based on the response). (Edit:) I want all calls to launch concurrently, and block until all calls are done/the response is acted on, and then return a new list with the info of each response.
I probably don't yet fully understand when to use launch/async, but I've tried to following with both launch (with joinAll), and async (with await).
fun processData(lstInputs: List<String>): List<response> {
val lstOfReturnData = mutableListOf<response>()
runBlocking {
withContext(Dispatchers.IO) {
val jobs = List(lstInputs.size) {
launch {
lstOfReturnData.add(networkCallToGetData(lstInputs[it]))
}
}
jobs.joinAll()
}
}
return lstofReturnData
What I am expecting to happen, is if my lstInputs is a size of 120, when all jobs are joined, my lstOfReturnData should also have a size of 120.
What actually is happening is inconsitent results. I'll run it once, and I get 118 in my final list, run it again, it's 120, run it again, it's 117, etc. In the networkCallToGetData() method, I am handling any exceptions, to at least return something for every request, regardless if the network call fails.
Can anybody help explain why I am getting inconsistent results, and what I need to do to ensure I am blocking appropriately and all jobs are being joined before moving on?
mutableListOf() creates an ArrayList, which is not thread-safe.
Try using ConcurrentLinkedQueue instead.
Also, do you use the stable version of Kotlin/Kotlinx.coroutine (not the old experimental one)? In the stable version, with the introduction of structured concurrency, there is no need to write jobs.joinAll anymore. launch is an extesion function of runBlocking which will launch new coroutines in the scope of the runBlocking and the runBlocking scope will automatically wait for all the launched jobs to finsish. So the code above can be shorten to
val lstOfReturnData = ConcurrentLinkedQueue<response>()
runBlocking {
lstInputs.forEach {
launch(Dispatches.IO) {
lstOfReturnData.add(networkCallToGetData(it))
}
}
}
return lstOfReturnData
runBlocking blocks current thread interruptibly until its completion. I guess it's not what you want. If I think wrong and you want to block the current thread than you can get rid of coroutine and just make network call in the current thread:
val lstOfReturnData = mutableListOf<response>()
lstInputs.forEach {
lstOfReturnData.add(networkCallToGetData(it))
}
But if it is not your intent you can do the following:
class Presenter(private val uiContext: CoroutineContext = Dispatchers.Main)
: CoroutineScope {
// creating local scope for coroutines
private var job: Job = Job()
override val coroutineContext: CoroutineContext
get() = uiContext + job
// call this to cancel job when you don't need it anymore
fun detach() {
job.cancel()
}
fun processData(lstInputs: List<String>) {
launch {
val deferredList = lstInputs.map {
async(Dispatchers.IO) { networkCallToGetData(it) } // runs in parallel in background thread
}
val lstOfReturnData = deferredList.awaitAll() // waiting while all requests are finished without blocking the current thread
// use lstOfReturnData in Main Thread, e.g. update UI
}
}
}
Runblocking should mean you don't have to call join.
Launching a coroutine from inside a runblocking scope should do this for you.
Have you tried just:
fun processData(lstInputs: List<String>): List<response> {
val lstOfReturnData = mutableListOf<response>()
runBlocking {
lstInputs.forEach {
launch(Dispatchers.IO) {
lstOfReturnData.add(networkCallToGetData(it))
}
}
}
return lstofReturnData