2

I don't understand why in the program below GlobalScope.launch instruction doesn't finish its task.

I do understand that runBlocking has no control over GlobalScope and it's usually bad to use it, but that doesn't make me know why instructions inside GlobalScope.launch {} doesn't execute as expected.

The code snippet:

package coroutines

import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import java.io.File

fun main() = runBlocking<Unit> {
    GlobalScope.launch {
        val file = File(javaClass.getResource("/coroutines_file.txt").path)

        file.printWriter().use { out ->
            repeat(10) { i ->
                delay(100)
                out.println(i.toString())
            }
        }
    }
}

Expected output inside coroutines_file:

0
1
2
3
4
5
6
7
8
9

Actual output:

An empty file.

Zain
  • 37,492
  • 7
  • 60
  • 84
HaKIM
  • 23
  • 4
  • [Global coroutines are like daemon threads](https://kotlinlang.org/docs/reference/coroutines/basics.html#global-coroutines-are-like-daemon-threads). `.join()` it if you want to wait for its completion. – George Leung Dec 09 '20 at 15:52

1 Answers1

0

GlobalScope is just an escape hatch from structured concurrency. It can't be cancelled, it doesn't even have a Job associated with it, so it doesn't offer a top-level facility that tracks all the jobs launched inside it.

On the other hand, runBlocking establishes its own scope that you should inherit for the launched coroutine, and it automatically ensures all the child coroutines run to completion.

runBlocking<Unit> {
    launch(Dispatchers.IO) {
        val file = File(javaClass.getResource("/coroutines_file.txt").path)
        file.printWriter().use { out ->
            repeat(10) { i ->
                delay(100)
                out.println(i.toString())
            }
        }
    }
}
Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • What does kill the GlobalScope process and why? I'm pretty new to JVM world. I don't understand why the program stops, even tho there is a job to do i.e. instructions inside GlobalScope.launch, and it wasn't finished nor told to stop. – HaKIM Dec 10 '20 at 17:23
  • 1
    Coroutine scope is not a process, it is just an object holding a `CoroutineContext`, and Kotlin makes it easy to pass the scope object down the coroutine hirerarchy. Specifically, `GlobalScope` defines a completely empty `CoroutineContext`, so you end up using the `Default` coroutine dispatcher. This maps to the JVM's global threadpool, `ForkJoinPool.commonPool()`, and that one uses threads marked as "daemon" which in Java means that it gets automatically killed when all non-daemon threads have ended. – Marko Topolnik Dec 10 '20 at 17:29
  • Oh, now I get it! Thank you a lot! – HaKIM Dec 10 '20 at 21:14
  • "there's no facility in it to await the completion of jobs launched inside it" is a bit confusing. It sounds like one can't even `.join()` the `Job`s `launch`ed inside `GlobalScope`. – George Leung Dec 11 '20 at 09:29