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

[Kotlin Coroutines] 6장. 코루틴 빌더

개요

launch 빌더

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@OptIn(DelicateCoroutinesApi::class)
fun main() {
    GlobalScope.launch {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    GlobalScope.launch {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    GlobalScope.launch {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    println("Hello,")
    Thread.sleep(2000L)
}

// Hello,
// World! DefaultDispatcher-worker-1
// World! DefaultDispatcher-worker-3
// World! DefaultDispatcher-worker-2
//
// Process finished with exit code 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
fun main() {
    thread(isDaemon = true) {
        Thread.sleep(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    thread(isDaemon = true) {
        Thread.sleep(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    thread(isDaemon = true) {
        Thread.sleep(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    println("Hello,")
    Thread.sleep(2000L)
}

// Hello,
// World! Thread-0
// World! Thread-2
// World! Thread-1
//
// Process finished with exit code 0

runBlocking 빌더

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
fun main() {
    runBlocking {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    runBlocking {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    runBlocking {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    println("Hello,")
}

// World! main
// World! main
// World! main
// Hello,
//
// Process finished with exit code 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
fun main() {
    Thread.sleep(1000L)
    println("World!")
    Thread.sleep(1000L)
    println("World!")
    Thread.sleep(1000L)
    println("World!")
    println("Hello,")
}

// World!
// World!
// World!
// Hello,
//
// Process finished with exit code 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
fun main() =
    runBlocking {
        GlobalScope.launch {
            delay(1000L)
            println("World! ${Thread.currentThread().name}")
        }
        GlobalScope.launch {
            delay(1000L)
            println("World! ${Thread.currentThread().name}")
        }
        GlobalScope.launch {
            delay(1000L)
            println("World! ${Thread.currentThread().name}")
        }
        println("Hello,")
        delay(2000L) // still needed
    }

// Hello,
// World! DefaultDispatcher-worker-2
// World! DefaultDispatcher-worker-1
// World! DefaultDispatcher-worker-3
//
// Process finished with exit code 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@OptIn(DelicateCoroutinesApi::class)
suspend fun main() {
    GlobalScope.launch {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    GlobalScope.launch {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    GlobalScope.launch {
        delay(1000L)
        println("World! ${Thread.currentThread().name}")
    }
    println("Hello,")
    delay(2000L)
}

// Hello,
// World! DefaultDispatcher-worker-2
// World! DefaultDispatcher-worker-1
// World! DefaultDispatcher-worker-3
//
// Process finished with exit code 0

async 빌더

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
@OptIn(DelicateCoroutinesApi::class)
fun main() =
    runBlocking {
        val resultDeferred: Deferred<Int> =
            GlobalScope.async {
                delay(1000L)
                42
            }
        // do other stuff...
        val result: Int = resultDeferred.await() // (1 sec)
        println(result) // 42
        // or just
        println(resultDeferred.await()) // 42
    }
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyDeferredCoroutine(newContext, block) else
        DeferredCoroutine<T>(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@OptIn(DelicateCoroutinesApi::class)
fun main() =
    runBlocking {
        val res1 =
            GlobalScope.async {
                delay(1000L)
                "Text 1"
            }
        val res2 =
            GlobalScope.async {
                delay(3000L)
                "Text 2"
            }
        val res3 =
            GlobalScope.async {
                delay(2000L)
                "Text 3"
            }
        println(res1.await())
        println(res2.await())
        println(res3.await())
    }

구조화된 동시성

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyStandaloneCoroutine(newContext, block) else
        StandaloneCoroutine(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public fun <T> CoroutineScope.async(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> T
): Deferred<T> {
    val newContext = newCoroutineContext(context)
    val coroutine = if (start.isLazy)
        LazyDeferredCoroutine(newContext, block) else
        DeferredCoroutine<T>(newContext, active = true)
    coroutine.start(start, coroutine, block)
    return coroutine
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Throws(InterruptedException::class)
public actual fun <T> runBlocking(context: CoroutineContext, block: suspend CoroutineScope.() -> T): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    val currentThread = Thread.currentThread()
    val contextInterceptor = context[ContinuationInterceptor]
    val eventLoop: EventLoop?
    val newContext: CoroutineContext
    if (contextInterceptor == null) {
        // create or use private event loop if no dispatcher is specified
        eventLoop = ThreadLocalEventLoop.eventLoop
        newContext = GlobalScope.newCoroutineContext(context + eventLoop)
    } else {
        // See if context's interceptor is an event loop that we shall use (to support TestContext)
        // or take an existing thread-local event loop if present to avoid blocking it (but don't create one)
        eventLoop = (contextInterceptor as? EventLoop)?.takeIf { it.shouldBeProcessedFromContext() }
            ?: ThreadLocalEventLoop.currentOrNull()
        newContext = GlobalScope.newCoroutineContext(context)
    }
    val coroutine = BlockingCoroutine<T>(newContext, currentThread, eventLoop)
    coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
    return coroutine.joinBlocking()
}

현업에서의 코루틴 사용

coroutineScope 사용하기

kotlin_coroutines_library_elements.svg

요약