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

[Kotlin Coroutines] 17장. 셀렉트

introduction

지연되는 값 선택하기

 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
private suspend fun requestData1(): String {
    delay(100_000)
    return "Data1"
}

private suspend fun requestData2(): String {
    delay(1000)
    return "Data2"
}

private val scope = CoroutineScope(SupervisorJob())

private suspend fun askMultipleForData(): String {
    val defData1 = scope.async { requestData1() }
    val defData2 = scope.async { requestData2() }
    return select {
        defData1.onAwait { it }
        defData2.onAwait { it }
    }
}

suspend fun main(): Unit =
    coroutineScope {
        println(askMultipleForData())
    }

// (1 sec)
// Data2
 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
private suspend fun requestData1(): String {
    delay(10_000)
    return "Data1"
}

private suspend fun requestData2(): String {
    delay(1000)
    return "Data2"
}

private suspend fun askMultipleForData(): String =
    coroutineScope {
        select {
            async { requestData1() }.onAwait { it }
            async { requestData2() }.onAwait { it }
        }.also { coroutineContext.cancelChildren() }
    }

suspend fun main(): Unit =
    coroutineScope {
        println(askMultipleForData())
    }

// (1 sec)
// Data2

채널에서 값 선택하기

 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
32
33
34
35
36
37
@OptIn(ExperimentalCoroutinesApi::class)
private fun CoroutineScope.produceString( // <-- suspend 없어도 잘 실행됨
    s: String,
    time: Long,
) = produce {
    while (true) {
        delay(time)
        send(s)
    }
}

fun main() =
    runBlocking {
        val fooChannel = produceString("foo", 210L)
        val barChannel = produceString("BAR", 500L)

        repeat(7) {
            select {
                fooChannel.onReceive {
                    println("From fooChannel: $it")
                }
                barChannel.onReceive {
                    println("From barChannel: $it")
                }
            }
        }

        coroutineContext.cancelChildren()
    }

// From fooChannel: foo
// From fooChannel: foo
// From barChannel: BAR
// From fooChannel: foo
// From fooChannel: foo
// From barChannel: BAR
// From fooChannel: foo
 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
fun main(): Unit =
    runBlocking {
        val c1 = Channel<Char>(capacity = 2)
        val c2 = Channel<Char>(capacity = 2)

        // Send values
        launch {
            for (c in 'A'..'H') {
                delay(400)
                select {
                    c1.onSend(c) { println("Sent $c to 1") }
                    c2.onSend(c) { println("Sent $c to 2") }
                }
            }
        }

        // Receive values
        launch {
            while (true) {
                delay(1000)
                val c =
                    select {
                        c1.onReceive { "$it from 1" }
                        c2.onReceive { "$it from 2" }
                    }
                println("Received $c")
            }
        }
    }

// Sent A to 1
// Sent B to 1
// Received A from 1
// Sent C to 1
// Sent D to 2
// Received B from 1
// Sent E to 1
// Sent F to 2
// Received C from 1
// Sent G to 1
// Received E from 1
// Sent H to 1
// Received G from 1
// Received H from 1
// Received D from 2
// Received F from 2
// (Not terminated)

요약