=================
== The Archive ==
=================

[Kotlin Coroutines] 8장. 잡과 자식 코루틴 기다리기

개요

Job 이란 무엇인가?

kotlin_coroutines_job_status.svg

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
suspend fun main() =
    coroutineScope {
        // Job created with a builder is active
        val job = Job()
        println(job) // JobImpl{Active}@ADD
        // until we complete it with a method
        job.complete()
        println(job) // JobImpl{Completed}@ADD

        // launch is initially active by default
        val activeJob =
            launch {
                delay(1000)
            }
        println(activeJob) // StandaloneCoroutine{Active}@ADD
        // here we wait until this job is done
        activeJob.join() // (1 sec)
        println(activeJob) // StandaloneCoroutine{Completed}@ADD

        // launch started lazily is in New state
        val lazyJob =
            launch(start = CoroutineStart.LAZY) {
                delay(1000)
            }
        println(lazyJob) // LazyStandaloneCoroutine{New}@ADD
        // we need to start it, to make it active
        lazyJob.start()
        println(lazyJob) // LazyStandaloneCoroutine{Active}@ADD
        lazyJob.join() // (1 sec)
        println(lazyJob) // LazyStandaloneCoroutine{Completed}@ADD
    }
상태isActiveisCompletedisCancelled
New (지연 시작될 때 시작 상태)falsefalsefalse
Active (시작 상태 기본값)truefalsefalse
Completing (일시적인 상태)truefalsefalse
Cancelling (일시적인 상태)falsefalsetrue
Cancelled (최종 상태)falsetruetrue
Completed (최종 상태)falsetruefalse

코루틴 빌더는 부모의 잡을 기초로 자신들의 잡을 생성한다

1
2
3
4
5
6
7
8
fun main(): Unit =
    runBlocking {
        val job: Job =
            launch {
                delay(1000)
                println("Test")
            }
    }
1
2
3
4
5
6
7
8
9
fun main(): Unit =
    runBlocking {
        val deferred: Deferred<String> =
            async {
                delay(1000)
                "Test"
            }
        val job: Job = deferred
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fun main(): Unit =
    runBlocking {
        val name = CoroutineName("Some name")
        val job = Job()

        launch(name + job) {
            val childName = coroutineContext[CoroutineName]
            assert(childName == name) // true
            val childJob = coroutineContext[Job]
            assert(childJob == null)
            assert(childJob != job) // false
            assert(childJob == job.children.first()) // true
        }
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fun main(): Unit =
    runBlocking {
        val job: Job =
            launch {
                delay(1000)
            }

        val parentJob: Job = coroutineContext.job
        // or coroutineContext[Job]!!
        assert(job != parentJob) // false
        val parentChildren: Sequence<Job> = parentJob.children
        assert(parentChildren.first() == job) // true
    }
1
2
3
4
5
6
7
fun main(): Unit =
    runBlocking {
        launch(Job()) { // the new job replaces one from parent
            delay(1000)
            println("Will not be printed")
        }
    } // (prints nothing, finishes immediately)

자식들 기다리기

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
fun main(): Unit =
    runBlocking {
        val job1 =
            launch {
                delay(1000)
                println("Test1")
            }
        val job2 =
            launch {
                delay(2000)
                println("Test2")
            }

        job1.join()
        job2.join()
        println("All tests are done")
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
fun main(): Unit =
    runBlocking {
        launch {
            delay(1000)
            println("Test1")
        }
        launch {
            delay(2000)
            println("Test2")
        }

        val children =
            coroutineContext[Job]
                ?.children

        val childrenNum = children?.count()
        println("Number of children: $childrenNum")
        children?.forEach { it.join() }
        println("All tests are done")
    }

잡 팩토리 함수

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
suspend fun main(): Unit =
    coroutineScope {
        val job = Job()
        launch(job) { // the new job replaces one from parent
            delay(1000)
            println("Text 1")
        }
        launch(job) { // the new job replaces one from parent
            delay(2000)
            println("Text 2")
        }
        job.join() // Here we will await forever
        println("Will not be printed")
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
suspend fun main(): Unit =
    coroutineScope {
        val job = Job()
        launch(job) { // the new job replaces one from parent
            delay(1000)
            println("Text 1")
        }
        launch(job) { // the new job replaces one from parent
            delay(2000)
            println("Text 2")
        }
        job.children.forEach { it.join() }
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
suspend fun main(): Unit =
    coroutineScope {
        val parentJob = Job()
        val job = Job(parentJob)
        launch(job) {
            delay(1000)
            println("Text 1")
        }
        launch(job) {
            delay(2000)
            println("Text 2") // This will not be printed
        }
        delay(1100)
        parentJob.cancel()
        job.children.forEach { it.join() }
    }