๊นจ์•Œ ๊ฐœ๋… ๐Ÿ“‘/Kotlin

[Kotlin] Coroutines - runBlocking

interfacer_han 2024. 2. 13. 17:52

#1 ์ด์ „ ๊ธ€

[Kotlin] Coroutines - Coroutine builder

#1 Coroutine builder kotlinx-coroutines-core Core primitives to work with coroutines. Coroutine builder functions: Coroutine dispatchers implementing CoroutineDispatcher: More context elements: Synchronization primitives for coroutines: Top-level suspendin

kenel.tistory.com

ํ•ด๋‹น ๊ฒŒ์‹œ๊ธ€์˜ #2์—์„œ ์ด์–ด์ง„๋‹ค.
 

import kotlinx.coroutines.*

fun main() {
    println("Start")

    runBlocking {
        delay(5000) // 5์ดˆ ๋Œ€๊ธฐ
    }
    
    println("End")
}

/* ์ถœ๋ ฅ ๊ฒฐ๊ณผ
Start
End
*/

runBlocking์€ ์ด๋ฆ„์—์„œ ๋ณด๋“ฏ, ํ˜„์žฌ ์Šค๋ ˆ๋“œ๋ฅผ Blocking(๋ธ”๋กœํ‚น)ํ•˜๋Š” ํ•จ์ˆ˜๋‹ค. ๊ทธ๋ฆฌ๊ณ  runBlocking { ... } ์˜์—ญ ๋‚ด์˜ ์ฝ”๋ฃจํ‹ด ์ฝ”๋“œ๋ฅผ ํ˜„์žฌ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ํ•œ๋‹ค. runBlocking { ... }์ด ๋๋‚จ๊ณผ ๋™์‹œ์— ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ Blocking์ด ํ•ด์ œ๋œ๋‹ค. ์ •๋ฆฌํ•˜๋ฉด, Blocking๋œ ์Šค๋ ˆ๋“œ์—์„œ runBlocking { ... } ์† ์ฝ”๋“œ๋งŒ ์˜ˆ์™ธ์ ์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋ฃจํ‹ด์„ ์“ฐ๋Š” ์ด์œ ๋ฅผ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์Šค๋ ˆ๋“œ๋ฅผ Blockingํ•ด์„  ์•ˆ ๋œ๋‹ค. ๋ณ‘๋ ฌ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  Coroutine์„ ์“ฐ๋Š” ๊ฒƒ์ด๋‹ˆ ๋ง์ด๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ runBlocking๋งŒ ๋‚˜๋จธ์ง€ Coroutine builder(launch(), asycn(), produce())์™€ ๋‹ฌ๋ฆฌ CoroutineScope์˜ ํ™•์žฅ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค. runBlocking์˜ ์ •์ฒด๋Š” ๋Œ€์ฒด ๋ฌด์—‡์ธ๊ฐ€? 
 

#2 ์ฝ”๋“œ์˜ ๋™๊ธฐ์„ฑ ๋ฐ ๋น„๋™๊ธฐ์„ฑ

[Kotlin] Coroutines - ๋™๊ธฐ ์ฝ”๋“œ, ๋น„๋™๊ธฐ ์ฝ”๋“œ

#1 ๋™๊ธฐ ์ฝ”๋“œ vs ๋น„๋™๊ธฐ ์ฝ”๋“œ #1-1 ๊ตฌ๋ถ„ํ•˜๊ธฐ ์ฝ”๋ฃจํ‹ด์„ ์ œ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„  ๋จผ์ €, '๋™๊ธฐ ์ฝ”๋“œ'์™€ '๋น„๋™๊ธฐ ์ฝ”๋“œ(= ์ฝ”๋ฃจํ‹ด ์ฝ”๋“œ)'๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•  ์ค„ ์•Œ์•„์•ผ ํ•œ๋‹ค. ๋‘˜์„ ๊ตฌ๋ถ„ํ•˜๋Š” ๊ธฐ์ค€์€ ์‰ฝ๊ฒŒ ๋ง

kenel.tistory.com

'๋™๊ธฐ ์ฝ”๋“œ' ๋ฐ '๋น„๋™๊ธฐ ์ฝ”๋“œ'์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ์ฝ์–ด์•ผ ์ด ๋‹ค์Œ์„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.
 

#3 runBlocking

#3-1 ์ •์ฒด

launch, async, produce๋Š” '๋น„๋™๊ธฐ ์ฝ”๋“œ'๋ฅผ '๋™๊ธฐ ์ฝ”๋“œ'์˜ ์˜์—ญ์— ๋‘˜ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“œ๋Š” ํฌ์žฅ์ง€๋‹ค. ๋ฐ˜๋ฉด, runBlocking์€ '๋น„๋™๊ธฐ ์ฝ”๋“œ'๋ฅผ '๋™๊ธฐ ์ฝ”๋“œ'๋กœ ๋งŒ๋“œ๋Š” ํฌ์žฅ์ง€๋‹ค. 1์ดˆ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” delay(1000)์ด๋ผ๋Š” '๋น„๋™๊ธฐ ์ฝ”๋“œ'๋ฅผ ์˜ˆ๋กœ ๋“ค์–ด ๋ณด๊ฒ ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ '๋™๊ธฐ ์ฝ”๋“œ'์˜ ์˜์—ญ์— ๋‘˜ ์ˆœ ์—†๋‹ค. ์ด ์„ธ์ƒ์— ๋ถˆ๊ฐ€๋Šฅ์ด๋ž€ ์—†๋‹ค์ง€๋งŒ, ์ ์–ด๋„ ์—ฌ๊ธฐ์—์„  Kotlin ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ‡ด์งœ๋ฅผ ๋†“๊ธฐ์— ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ์ด ๋•Œ runBlocking { ... }์œผ๋กœ delay(1000)์„ ๊ฐ์‹ธ๋ฉด, ์ปดํŒŒ์ผ๋Ÿฌ๋‹˜์ด ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ํ—ˆ๋ฝํ•ด์ค€๋‹ค.
 

#3-2 ๋น„๋™๊ธฐ ์ฝ”๋“œ๊ฐ€ ๋™๊ธฐ ์ฝ”๋“œ ์˜์—ญ์— ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ์ œ

#3-1์˜ '์ปดํŒŒ์ผ๋Ÿฌ์˜ ํ—ˆ๋ฝ'์€ runBlocking์ด ํ˜„์žฌ ์Šค๋ ˆ๋“œ๋ฅผ Blocking(๋ธ”๋กœํ‚น)ํ•œ๋‹ค๋Š” ๊ฒƒ์— ๊ทผ๊ฑฐ๋œ ํ—ˆ๋ฝ์ด๋‹ค. ์Šค๋ ˆ๋“œ๋ฅผ Block(๋ฉˆ์ถค)ํ•จ์œผ๋กœ์จ runBlocking { ... }์˜ ์•ˆ๊ณผ ๋ฐ–์— '์ˆœ์ฐจ์„ฑ'์„ ๋ถ€์—ฌํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. runBlocking์ด ์‹œ์ž‘๋˜๋ฉด(= '{' ๋’ค๋ถ€ํ„ฐ) ํ˜„์žฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ถ€๋ถ„์ ์œผ๋กœ Blocking๋œ๋‹ค. ๋”ฐ๋ผ์„œ runBlocking { ... } ์•ˆ์— ๋“ค์–ด์˜ค๊ธฐ ์ „์˜ ์ž‘์—…์ด runBlocking { ... } ๋‚ด์—์„œ ์ˆ˜ํ–‰๋˜์ง€ ์•Š์„ ๊ฒƒ์ž„์ด ๋ณด์žฅ๋œ๋‹ค. ๋ถ€๋ถ„์ ์œผ๋กœ Blocking๋œ๋‹ค๋Š” ๋ง์€, runBlocking { ... } ๋ฐ–์— ์žˆ๋Š” ๋ถ€๋ถ„์ด Blocking๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. runBlocking { ... } ์•ˆ์— ์žˆ๋Š” ์ฝ”๋“œ๋“ค๋งŒ ์˜ˆ์™ธ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค.
 
runBlocking์ด ๋๋‚˜๋ฉด(= '}'๋ฅผ ๋งŒ๋‚˜๋ฉด) ์Šค๋ ˆ๋“œ์— ๊ฐ€ํ–ˆ์—ˆ๋˜ ๋ถ€๋ถ„์  Blocking์„ ํ•ด์ œํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ์ „์— ์ˆ˜ํ–‰๋˜๋Š” ๋™์ž‘์ด ์žˆ๋‹ค. ๋ฐ”๋กœ, runBlocking ๋‚ด์˜ ๋ชจ๋“  ์ฝ”๋ฃจํ‹ด์ด ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰, join(), await(), receive() ๋”ฐ์œ„๊ฐ€ ์•”์‹œ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค๋Š” ์–˜๊ธฐ๋‹ค. ๊ทธ๋ž˜์•ผ runBlocking ๋‚ด๋ถ€์˜ ์ž‘์—…์ด runBlocking { ... } ๋ฐ–์— ์žˆ๋Š” ์ž‘์—…๊ณผ ๋™์‹œ ์‹คํ–‰๋œ๋‹ค๊ฑฐ๋‚˜ ํ•˜๋Š” ์ผ์ด ์—†์„ ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฆ‰, runBlocking { ... } ๋ฐ–์ด ๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜์—ญ์ž„์„ ๋ณด์žฅํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ ์ž…์žฅ์—์„œ ๋ณด๋ฉด, ๋™๊ธฐ ์ฝ”๋“œ A โ†’ B โ†’ runBlocking { ... } โ†’ E๊ฐ€ ์ˆœ์ฐจ์ ์ด๋ฉฐ ์—ฐ์†์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค. ์Šค๋ ˆ๋“œ ์ž…์žฅ์—์„  runBlocking { ... }์ด ๋™๊ธฐ ์ฝ”๋“œ๋กœ ๋ณด์ด๋Š” ๊ฒƒ์ด๋‹ค.
 

#3-3 runBlocking์˜ ์šฉ๋„

runBlocking์˜ ์‹ค์šฉ์„ฑ์€ ๋‹ค๋ฅธ Coroutine builder๋“ค์— ๋น„ํ•˜๋ฉด ์—†์–ด๋ณด์ธ๋‹ค. ์•ž์„œ ๋งํ–ˆ๋“ฏ, ์šฐ๋ฆฌ๋Š” ๋ณ‘๋ ฌ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๋ ค๊ณ  Coroutine์„ ์“ฐ๋Š” ๊ฒƒ์ด๋‹ˆ ๋ง์ด๋‹ค. ๊ทธ๋ž˜์„œ์ธ์ง€, runBlocking์€ ๋Œ€๋ถ€๋ถ„ ์ฝ”๋“œ ํ…Œ์ŠคํŠธ, ๋””๋ฒ„๊น… ์šฉ๋„๋กœ ์“ฐ์ธ๋‹ค๊ณ  ํ•œ๋‹ค. ๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜์—ญ์„ ํ•ด์น˜์ง€ ์•Š์œผ๋ฉด์„œ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ฝ”๋ฃจํ‹ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

#3-4 ์—ฌ๋‹ด

์—ฌ๋‹ด์œผ๋กœ, runBlocking๋ฅผ '๋น„๋™๊ธฐ ์ฝ”๋“œ ์˜์—ญ'์—์„œ ์“ฐ๋Š” ๊ฑด ์“ธ ๋ฐ ์—†๋Š” ์ง“์ด๋‹ค. ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, runBlocking์˜ ์—ญํ• ์„ ์ƒ๊ฐํ•˜๋ฉด ๋‹น์—ฐํ•˜๋‹ค. ๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜์—ญ์— ๋น„๋™๊ธฐ ์ฝ”๋“œ๋Š” ์˜ฌ ์ˆ˜ ์—†์ง€๋งŒ, ๋น„๋™๊ธฐ ์ฝ”๋“œ ์˜์—ญ์— ๋™๊ธฐ ์ฝ”๋“œ๋Š” ์–ผ๋งˆ๋“ ์ง€ ํ—ˆ์šฉ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ, runBlocking์€ ์ผ๋ฐ˜์ ์œผ๋กœ '๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜์—ญ'์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ๋ณด๋ฉด ๋œ๋‹ค.
 

#4 ์ฃผ์˜์ 

import kotlinx.coroutines.*

// ์ฝ”๋“œ 1
fun main() {

    println("main() is running on ${Thread.currentThread().name}")

    runBlocking {
        println("runBlocking is running on ${Thread.currentThread().name}")

        launch {
            delay(3000)
            println("launch() is running on ${Thread.currentThread().name}")
        }
    }

    // ...
}

/* โ†‘ โ†‘ โ†‘ ์ถœ๋ ฅ ๊ฒฐ๊ณผ
main() is running on main
runBlocking is running on main
launch() is running on main
*/

---

// ์ฝ”๋“œ 2
fun main() {

    println("main() is running on ${Thread.currentThread().name}")

    runBlocking {
        println("runBlocking is running on ${Thread.currentThread().name}")

        CoroutineScope(Dispatchers.Default).launch {
            println("launch() is running on ${Thread.currentThread().name}")
        }
    }

    // ...
}

/* โ†‘ โ†‘ โ†‘ ์ถœ๋ ฅ ๊ฒฐ๊ณผ
main() is running on main
runBlocking is running on main
launch() is running on DefaultDispatcher-worker-1
*/

'์ฝ”๋“œ 1'๊ณผ '์ฝ”๋“œ 2'๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ์ฝ”๋“œ๋‹ค. ์ถœ๋ ฅ ๊ฒฐ๊ณผ๋„ ์„œ๋กœ ๋‹ค๋ฅธ ๋ชจ์Šต์„ ๋ณด์—ฌ์ค€๋‹ค. ์ฝ”๋“œ 1๊ณผ 2 ๋ชจ๋‘ runBlocking { ... }์œผ๋กœ runBlocking์ด ์œ„์น˜ํ•œ ์Šค๋ ˆ๋“œ (์—ฌ๊ธฐ์„œ๋Š” main()์„ ์‹คํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ(์ดํ•˜ ๋ฉ”์ธ ์Šค๋ ˆ๋“œ))์˜ ์ž‘๋™์„ Blockํ•œ๋‹ค๋Š” ์ ์€ ๊ฐ™๋‹ค. ํ•˜์ง€๋งŒ ์ฝ”๋“œ 1์˜ launch()๊ฐ€ runBlocking์˜ ์ž์‹์œผ๋กœ์„œ ๋ฉ”์ธ ์Šค๋ ˆ๋“œํ’€์—์„œ ์‹คํ–‰๋˜๋Š” ๋ฐ˜๋ฉด, ์ฝ”๋“œ 2์˜ launch()๋Š” ์ƒˆ๋กœ์šด ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„์—์„œ ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹น๋ฐ›์•„ ์™„์ „ํžˆ ๋…๋ฆฝ์ ์ธ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
 

#5 ์š”์•ฝ

์Šค๋ ˆ๋“œ ์ž…์žฅ์—์„œ runBlocking { ... }์€ ๋™๊ธฐ ์ฝ”๋“œ๋กœ ๋ณด์ธ๋‹ค. ์‹ค์ œ๋กœ๋„ ๊ทธ๋ ‡๋‹ค.