03
29

https://kotlinlang.org/docs/coroutines-basics.html

 

Coroutines basics | Kotlin

 

kotlinlang.org

์œ„ ๋งํฌ๋ฅผ ๊ณต๋ถ€ํ•˜๋ฉฐ ๋‚จ๊ธฐ๋Š” ๊ธฐ๋ก์ด๋‹ค.

 

์ฝ”๋ฃจํ‹ด Coroutine

a

์ฝ”๋ฃจํ‹ด์€ ์ง€์—ฐ๊ฐ€๋Šฅํ•œ ์ธ์Šคํ„ด์Šค์ด๋‹ค. ์œ„ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ์“ฐ๋ ˆ๋“œ์™€ ๋น„์Šทํ•˜๊ฒŒ ๋Œ์ง€๋งŒ ํ•œ ์“ฐ๋ ˆ๋“œ ์•ˆ์—์„œ ์ง€์—ฐ์ž‘์—…์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์ง€์—ฐ๋œ๋‹ค๋Š” ์˜๋ฏธ๋Š” ํŠน์ •์‹œ์ ์— ๋ฉˆ์ถฐ๋†“๊ณ  ์—ฐ์‚ฐํ•œ๋‹ค์Œ, ์ด๊ฑธ ์‚ฌ์šฉํ•  ์ง€ ๋ง ์ง€ ๊ฒฐ์ •ํ•œ๋‹ค๊ณ  ์ดํ•ดํ•˜๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค. ์ฝ”๋ฃจํ‹ด์€ ์“ฐ๋ ˆ๋“œ์— ๋น„ํ•ด ์ ์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.  

fun main() = runBlocking {
    launch {
        delay(2000L)
        println("B!")
    }
    println("A")
}

์ƒ˜ํ”Œ ์ฝ”๋“œ๋ฅผ ์‚ด์ง๋งŒ ๋ฐ”๊ฟ”๋ดค๋‹ค. ์ฝ”๋“œ ์ˆœ์„œ์ƒ B->A๊ฐ€ ๋ผ์•ผํ•˜์ง€๋งŒ B๊ฐ€ 2์ดˆ ๋”œ๋ ˆ์ด ๊ฑธ๋ฆฌ๋Š”๋™์•ˆ์— A๊ฐ€ ๋จผ์ € ์ถœ๋ ฅ๋ผ์„œ A->B๊ฐ€ ๋œ๋‹ค. 

 

runBlocking{}

runBlocking์€ ์ฝ”๋ฃจํ‹ด ๋นŒ๋”์ด์ž ์ค‘๊ฐ„๋‹ค๋ฆฌ ์—ญํ• ์„ ํ•œ๋‹ค. main()ํ•จ์ˆ˜๋ฅผ runBlocking์œผ๋กœ ๋ฌถ์œผ๋ฉด์„œ ์ฝ”๋ฃจํ‹ด ์ฝ”๋“œ๋ฅผ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์คฌ๋‹ค. ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„๊ฐ€ ์•„๋‹Œ๊ณณ์—์„œ ์ฝ”๋ฃจํ‹ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ์ •ํ™•ํžˆ๋Š” runBlocking ๋‚ด๋ถ€์˜ ์ฝ”๋ฃจํ‹ด ์ฝ”๋“œ๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์ง€๊ธˆ ์‚ฌ์šฉ์ค‘์ธ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ ์œ (block)ํ•˜๋Š” ํ•จ์ˆ˜๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ ์œ ํ•˜๋ฉด ๋ฆฌ์†Œ์Šค ๋ถ€์กฑ์œผ๋กœ ์ธํ•œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์‹œ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 

launch{}

launch๋„ ์ฝ”๋ฃจํ‹ด ๋นŒ๋”(์ฝ”๋ฃจํ‹ด์„ ์ƒ์„ฑํ•˜๋Š” ์—ญํ• )์ด๋‹ค. launch๋กœ ๊ฐ์‹ผ ์Šค์ฝ”ํ”„๋Š” ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค. ํ˜„์žฌ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ ์œ ํ•˜์ง€ ์•Š์ง€๋งŒ ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„ ๋‚ด์—์„œ๋งŒ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค. Job์„ ๋ฐ˜ํ™˜ํ•˜๋Š”๋ฐ ์ด job์ด cancelled๋ผ๋ฉด ํ˜„์žฌ ์ฝ”๋ฃจํ‹ด์ด ์ทจ์†Œ๋œ๋‹ค.

 

์ฝ”๋ฃจํ‹ด์€ ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ ์›์น™(structured concurrency)์„ ๋”ฐ๋ฅธ๋‹ค๊ณ  ํ•œ๋‹ค. ์ƒˆ ์ฝ”๋ฃจํ‹ด์€ ์˜ค์ง ์ฝ”๋ฃจํ‹ด ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ตฌ๋ถ„ ํ•  ์ˆ˜ ์žˆ๋Š” ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„ ์•ˆ์—์„œ๋งŒ ์‹œ์ž‘๋  ์ˆ˜ ์žˆ๋‹ค. ๋ถ€๋ชจ ์ฝ”๋ฃจํ‹ด์€ ์ž์‹ ์ฝ”๋ฃจํ‹ด์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „๊นŒ์ง€ ์™„๋ฃŒ๋  ์ˆ˜ ์—†๋‹ค. ์ด ๋ถ€๋ถ„์ด ๋ˆ„๋ฝ, ๋ˆ„์ˆ˜๊ฐ€ ์—†์Œ์„ ๋ณด์žฅํ•˜๋Š” ์ด์œ ๋ผ๊ณ  ํ•œ๋‹ค.

 

launch ์•ˆ์˜ ์ฝ”๋“œ๋Š” ๋…๋ฆฝ์ ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ฝ”๋ฃจํ‹ด์€ ์ง€์—ฐ๊ฐ€๋Šฅํ•œ ์ž‘์—…์ด๋‹ค. ์ด ๋‘ ๊ฐœ๋ฅผ ํ•ฉ์น˜๋ฉด ๋‚˜์˜ค๋Š” ๊ฐœ๋…์ด suspend fun์ด๋‹ค.

suspend fun doWorld() {
    delay(2000)
    println("A")
}

 suspend๋กœ ์ง€์ •ํ•œ ํ•จ์ˆ˜๋Š” ์ฝ”๋ฃจํ‹ด ๋‚ด๋ถ€์—์„œ ์ผ๋ฐ˜ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์ž‘๋™ํ•œ๋‹ค. ๋˜ ์ด ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋˜ ๋‹ค๋ฅธ ์ž‘์—…์„ ์ง€์—ฐ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.


coroutineScope - ์Šค์ฝ”ํ”„ ๋นŒ๋” Scope builder

์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„๋ฅผ ์ œ๊ณตํ•˜๋Š” ์—ฌ๋Ÿฌ ์Šค์ฝ”ํ”„ ๋นŒ๋”๋“ค์ด ์žˆ๋Š”๋ฐ ๊ทธ์ค‘ ํ•˜๋‚˜๋กœ coroutineScope๊ฐ€ ์žˆ๋‹ค. 

runBlocking๊ณผ coroutineScope์˜ ์ฐจ์ด์ ์€ ์ง€์†์„ฑ์ด๋‹ค. runBlocking์€ ์“ฐ๋ ˆ๋“œ๋ฅผ ์•„์˜ˆ ์ ์œ ํ•ด๋ฒ„๋ฆฌ์ง€๋งŒ coroutineScope๋Š” ํ†ต์งธ๋กœ ๊ฐ€์ ธ๊ฐ€๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ํŠน์ • ์‹œ์ ์— ๋ฉˆ์ถฐ๋‘” ๋…๋ฆฝ๋œ ์“ฐ๋ ˆ๋“œ์ฒ˜๋Ÿผ ์ž‘๋™ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ runBlocking์€ ์ผ๋ฐ˜ํ•จ์ˆ˜, coroutineScope๋Š” suspending ํ•จ์ˆ˜์ด๋‹ค.

fun main() = runBlocking {
    doWorld()
}

suspend fun doWorld() = coroutineScope {  // this: CoroutineScope
    launch {
        delay(1000L)
        println("B")
    }
    println("A")
}

launch๋Š” ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„์•ˆ์—์„œ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— suspend fun์—์„œ launch๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์œผ๋ฉด coroutineScope๋กœ ๊ฐ์‹ธ์ฃผ๋ฉด ๋œ๋‹ค. ์œ„ ์ฝ”๋“œ์˜ ๊ฒฝ์šฐ coroutineScope๊ฐ€ ์ข…๋ฃŒ๋˜๊ณ ๋‚˜์„œ runBlocking์ด ์ข…๋ฃŒ๋œ๋‹ค.

// Concurrently executes both sections
suspend fun doWorld() = coroutineScope { // this: CoroutineScope
    launch {
        delay(2000L)
        println("A")
    }
    launch {
        delay(1000L)
        println("B")
    }
    println("C")
}

launch๋ฅผ ํ•œ ์ฝ”๋ฃจํ‹ด์Šค์ฝ”ํ”„ ์•ˆ์—์„œ 2๊ฐœ ์‹คํ–‰ํ•˜๋ฉด ๋™์‹œ์— ๋Œ์•„๊ฐ„๋‹ค.  ์œ„ ์ฝ”๋“œ๋Š” C->B->A๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

 

Job

์œ„์—์„œ launch๋Š” job์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๊ณ  ์ ์—ˆ์—ˆ๋‹ค.

val job = launch { // launch a new coroutine and keep a reference to its Job
    delay(1000L)
    println("B")
}
println("A")
job.join() // wait until child coroutine completes
println("C")

์ด ์ฝ”๋“œ๋Š” ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„ ์•ˆ์— ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. job.join()์„ ์ด์šฉํ•˜๋ฉด ์ง€๊ธˆ B๊ฐ€ ๋‹ด๊ธด job์ด ๋๋‚ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.  A->B->C๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค. ์ด job ์ธ์Šคํ„ด์Šค๋Š” ์ทจ์†Œ ์‹œํ‚ฌ์ˆ˜๋„์žˆ๋‹ค.

b

์ด ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ์‹คํ–‰์ค‘์— ์ทจ์†Œ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

a: https://ko.wikipedia.org/wiki/%EB%A9%80%ED%8B%B0%EC%8A%A4%EB%A0%88%EB%94%A9

b: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/

๋ฐ˜์‘ํ˜•

'Android ๐Ÿ–ฅ๏ธ > Coroutine๐Ÿ“–' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

Coroutine exceptions handling  (0) 2024.03.29
Asynchronous Flow - Intermediate flow operators~  (1) 2024.03.29
Coroutine context and dispatchers  (0) 2024.03.29
Coroutine Composing suspending functions  (0) 2024.03.29
Coroutine Cancellation and timeouts  (0) 2024.03.29
COMMENT