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

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

interfacer_han 2024. 2. 8. 12:26

๋ณธ ๊ฒŒ์‹œ๊ธ€์˜ #1 ~ #3์€ ๋™๊ธฐ์„ฑ ๋ฐ ๋น„๋™๊ธฐ์„ฑ์„ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์Šค๋ ˆ๋“œ์˜ ๊ฐœ๋…์— ๋Œ€ํ•ด ๊ณ ์˜์ ์ด๊ณ  ๋…ผ๋ฆฌ์ ์ธ ๋น„์•ฝ์„ ์‚ฌ์šฉํ–ˆ๋‹ค. ์ด ๊ธ€์„ ๋ณด๋Š” ๋ถ„์€ ๊ผญ #4์˜ ์ฃผ์˜ํ•  ์ ๊นŒ์ง€ ๋ด์ฃผ์…”์•ผ ํ•œ๋‹ค.

 

#1 ๋™๊ธฐ ์ฝ”๋“œ vs ๋น„๋™๊ธฐ ์ฝ”๋“œ

#1-1 ๊ตฌ๋ถ„ํ•˜๊ธฐ

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

 

#1-2 ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜ˆ์‹œ

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

suspend fun main() {
    println("Start")

    val myJob = CoroutineScope(Dispatchers.IO).launch {
        println("Coroutine code start")
        delay(2000)
        println("Coroutine code end")
    }

    var meaninglessNumber = 0
    for (i in 1..100000000) {
        meaninglessNumber += i
    }

    println("End")

    myJob.join()
}

/* ์ถœ๋ ฅ ๊ฒฐ๊ณผ
Start
Coroutine code start
End
Coroutine code end
*/

์œ„ ์ฝ”๋“œ์— '๋น„๋™๊ธฐ ์ฝ”๋“œ'๊ฐ€ ์กด์žฌํ•จ์€ ๋ถ„๋ช…ํ•˜๋‹ค. ์ฝ”๋“œ๊ฐ€ ์จ์ง„ ์ˆœ์„œ์™€ ์ถœ๋ ฅ ๊ฒฐ๊ณผ๊ฐ€ ๋น„๋ก€ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฆ‰, ์ˆœ์ฐจ์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

#2 ์Šค๋ ˆ๋“œ์˜ ๋ณ‘๋ ฌ ๊ตฌ์กฐ

#2-1 ํ•„์—ฐ์  ๋น„(้ž)์ˆœ์ฐจ์„ฑ

์ด ์˜ˆ์‹œ ๋„์‹๋„์—์„œ, ์›๋ž˜ ์Šค๋ ˆ๋“œ์— ์žˆ๋Š” A + B ์ถœ๋ ฅ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ํ•ด๋‹น ์‹œ์ ์—์„  A์˜ ๊ธด ์ž‘์—… ์‹œ๊ฐ„ ๋•Œ๋ฌธ์— ๊ทธ ๊ฐ’์ด ๋ญ”์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด์™€ ๊ฐ™์ด ๋ณ‘๋ ฌ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์„ฑํ•˜๋ฉด, ์‹œ์ฐจ๊ฐ€ ๋‚  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค. ๋ฌผ๋ก , ๋งˆ๋ฒ•์ฒ˜๋Ÿผ ๋ชจ๋“  ํƒ€์ด๋ฐ์ด ๋”ฑ๋”ฑ ๋งž์•„ ๋–จ์–ด์งˆ ์ˆ˜๋Š” ์žˆ๊ฒ ์ง€๋งŒ, ๊ทธ๊ฑด ๋™์ „ 100๊ฐœ๋ฅผ ๋˜์ ธ์„œ ์ „๋ถ€ ์•ž๋ฉด์ด ๋‚˜์˜ค์ง€ ์•Š์œผ๋ฆฌ๋ž€ ๋ฒ•์€ ์—†๋‹ค๋Š” ๋ง๊ณผ ๋˜‘๊ฐ™์€ ์†Œ๋ฆฌ๋‹ค. ์ฆ‰, ์ด๋Ÿฌํ•œ ์‹œ์ฐจ๋Š” ํ•„์—ฐ์ ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์‹œ์ฐจ๋ฅผ ๊ทน๋ณตํ•˜๋ ค๋ฉด, ์•„์ง ์™„๋ฃŒ๋˜์ง€ ์•Š์€ ์Šค๋ ˆ๋“œ๋ฅผ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค. ๋ฉˆ์ถฐ(Suspend)์•ผ ํ•œ๋‹ค๋Š” ๋ง์ด๋‹ค.

 

#2-2 Suspend๋ฅผ ์ถ”๊ฐ€ํ•œ ๋„์‹๋„

#2-1์„ ์ˆ˜์ •ํ•ด Suspendํ•˜๋Š” ์ž‘์—…์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.

 

#2-3 ๋น„๋™๊ธฐ ์ฝ”๋“œ์—์„œ Suspend๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ

์Šค๋ ˆ๋“œ ๋ณ‘๋ ฌ ๊ตฌ์กฐ์—์„œ Suspend๋Š” ๋ถ„๋ช… ํ•„์—ฐ์ ์ด์ง€๋งŒ, ํ•„์ˆ˜๋Š” ์•„๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ž‘์—… A์™€ B๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ๊ทธ๋ƒฅ ๊ณ„์‚ฐ๋งŒ ํ•˜๊ณ  ๋งˆ๋Š” ๊ฒฝ์šฐ๊ฐ€ ๊ทธ๋ ‡๋‹ค. ์‹œ์ฐจ๋ฅผ ๋งž์ถฐ์„œ ํ•  ์ž‘์—…์ด ์—†๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๊ตณ์ด Suspendํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰, Suspend๋Š” ๋ณ‘๋ ฌ ๊ตฌ์กฐ์—์„œ 'ํ•„์š”'ํ•˜์ง€๋งŒ, 'ํ•„์ˆ˜'๋Š” ์•„๋‹ˆ๋ผ๋Š” ์ด์•ผ๊ธฐ๋‹ค.

 

#3 ๋™๊ธฐ ์ฝ”๋“œ์˜ '์˜์—ญ' vs ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ '์˜์—ญ

๋™๊ธฐ ์ฝ”๋“œ ์˜์—ญ์€ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์—์„œ ์ž‘์—…์ด ์‹คํ–‰๋˜๋ฉฐ, ์ด์ „ ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋‹ค์Œ ์ž‘์—…์ด ์‹คํ–‰๋˜์ง€ ์•Š๋Š” ํ™˜๊ฒฝ์ด๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ผ์ƒ์ ์œผ๋กœ ์ ‘ํ•ด์˜จ ์ฝ”๋“œ์˜ ์ผ๋ฐ˜์ ์ธ ์˜์—ญ์ด ๊ทธ๋ ‡๋‹ค. ๋ฐ˜๋Œ€๋กœ ๋น„๋™๊ธฐ ์ฝ”๋“œ ์˜์—ญ์€ ์ž‘์—…๋“ค์ด ์ˆœ์ฐจ์„ฑ ์—†์ด ๋ณ‘๋ ฌ์ ์œผ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์„ ๋งํ•œ๋‹ค. Coroutine์€ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ์“ฐ ๋„๊ตฌ์ง€๋งŒ, Coroutine์ด๋ผ๊ณ  ๋ฐ˜๋“œ์‹œ ๋น„๋™๊ธฐ ์ฝ”๋“œ์ธ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค (์ฐธ์กฐ).
 
'๋™๊ธฐ ์ฝ”๋“œ'์˜ ์˜์—ญ์—” '๋น„๋™๊ธฐ ์ฝ”๋“œ'๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ์–ด์งธ์„œ? '๋น„๋™๊ธฐ ์ฝ”๋“œ'๋Š” ์ฝ”๋“œ๋ฅผ ์‹คํ–‰(Run)ํ•˜๋Š” ์ฃผ์ฒด์ธ ์‹œ์Šคํ…œ(Kotlin์˜ ๊ฒฝ์šฐ์—” Kotlin ๋Ÿฐํƒ€์ž„)์„ '๊ธฐ๋Œ€'ํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ž‘์—…์ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค๋Š” ์–˜๊ธฐ๋Š” ์‹œ์Šคํ…œ์ด ์–ธ์ œ ๊ทธ ์ฝ”๋“œ์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ๋Š” ์ง€๋ฅผ ์•Œ ์ˆ˜ ์—†๋‹ค๋Š” ์ด์•ผ๊ธฐ๋‹ค. ์ฆ‰, '๋น„๋™๊ธฐ ์ฝ”๋“œ'๋Š” ์‹œ์Šคํ…œ์—๊ฒŒ ๊ฐ’์„ ์ฆ‰๊ฐ์ ์œผ๋กœ ๋‚ด์ฃผ์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ์‹œ์Šคํ…œ์€ ์–ธ์  ๊ฐ„ ์ž‘์—…์ด ์™„๋ฃŒ(launch)๋˜๊ฑฐ๋‚˜ ๊ฐ’์„ ์ „๋‹ฌ(async, produce)ํ•ด์ค„ ๊ฑฐ๋ผ๊ณ  '๊ธฐ๋Œ€'๋งŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. '๊ธฐ๋Œ€'๋Š” '๊ธฐ๋‹ค๋ฆผ'์ด๋‹ค. ๊ธฐ๋‹ค๋ฆผ์€ '๊ฐ„ํ—์ ์ธ ๋ฉˆ์ถค'์ด๋‹ค. ๊ฐ„ํ—์ ์œผ๋กœ ๋ฉˆ์ถ”๋Š” ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ (์—๋Ÿฌ๊ฐ€ ๋‚˜์ง€ ์•Š๋Š” ํ•œ) ์ ˆ๋Œ€ ๋ฉˆ์ถ”์ง€ ์•Š์Œ์„ ๋ณด์žฅํ•˜๋Š” '๋™๊ธฐ ์ฝ”๋“œ ์˜์—ญ'์— ๋‘˜ ์ˆ˜ ์žˆ๊ฒ ๋Š”๊ฐ€? 
 
๋ฐ˜๋ฉด, '๋น„๋™๊ธฐ ์ฝ”๋“œ'์˜ ์˜์—ญ์—” '๋™๊ธฐ ์ฝ”๋“œ'๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋น„๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜์—ญ์ด๋ผ๊ณ  ๋ฐ˜๋“œ์‹œ ๋น„๋™๊ธฐ ์ฝ”๋“œ๋งŒ ์žˆ์„ ํ•„์š”๊ฐ€ ์—†๋‹ค. '๊ฐ„ํ—์  ๋ฉˆ์ถฐ์ง์ด ํ—ˆ์šฉ๋˜๋Š” ๊ณณ'์ด์ง€, '๋ฐ˜๋“œ์‹œ ๋ฉˆ์ถฐ์•ผํ•˜๋Š” ๊ณณ'์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

#1-2์˜ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, ๋น„๋™๊ธฐ ์ฝ”๋“œ๋Š” CoroutineScope๋ผ๋Š” ํฌ์žฅ์ง€์— ๋‘˜๋Ÿฌ์‹ธ์—ฌ ๋ฐ–์— ์žˆ๋Š” ๋™๊ธฐ ์ฝ”๋“œ์˜ ์˜์—ญ๊ณผ ๊ทธ ์˜์—ญ์ด ๋ถ„๋ช…ํžˆ ๊ตฌ๋ถ„๋จ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

#4 ์ฃผ์˜ํ•  ์  (์ฝ”๋ฃจํ‹ด์€ ๋ฌผ๋ฆฌ์  ์Šค๋ ˆ๋“œ๊ฐ€ ์•„๋‹ˆ๋‹ค)

#1 ~ #3์—์„œ๋Š” ๋™๊ธฐ์„ฑ ๋ฐ ๋น„๋™๊ธฐ์„ฑ์„ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋งˆ์น˜, ํ•˜๋‚˜์˜ ์ฝ”๋ฃจํ‹ด = ํ•˜๋‚˜์˜ (๋ฌผ๋ฆฌ์ ) ์Šค๋ ˆ๋“œ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ์„ค๋ช…ํ–ˆ๋‹ค. ํ•˜์ง€๋งŒ, ์ด๋Š” ์ดํ•ด๋ฅผ ์œ„ํ•œ ๊ณ ์˜์ ์ด๊ณ  ๋…ผ๋ฆฌ์ ์ธ ๋น„์•ฝ์ด๋‹ค. ์ฆ‰ ํ‹€๋ฆฐ ์„ค๋ช…์ด๋‹ค. ์Šค๋ ˆ๋“œ(Thread)๋Š” ์šด์˜์ฒด์ œ๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ ๊ฐ ์Šค๋ ˆ๋“œ๋Š” ๋ฌผ๋ฆฌ์ ์ธ CPU์— ํ• ๋‹น๋œ๋‹ค. ๋ฐ˜๋ฉด, ์ฝ”๋ฃจํ‹ด์€ ์ฝ”ํ‹€๋ฆฐ์ด๋ผ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ๋‹จ์œ„์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ์ผ์ข…์˜ ๋…ผ๋ฆฌ์  ์Šค๋ ˆ๋“œ๋‹ค.

 

์ฝ”๋ฃจํ‹ด์€ ๋…ผ๋ฆฌ์  ์Šค๋ ˆ๋“œ์ด๊ธฐ์—, ํ•˜๋‚˜์˜ ๋ฌผ๋ฆฌ์  ์Šค๋ ˆ๋“œ ์œ„์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ฝ”๋ฃจํ‹ด์ด ์ˆ˜ํ–‰๋  ์ˆ˜๋„ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, A๋ผ๋Š” ์Šค๋ ˆ๋“œ์—์„œ ์ฝ”๋ฃจํ‹ด a์™€ ์ฝ”๋ฃจํ‹ด b๊ฐ€ ์ˆ˜ํ–‰๋˜๋Š” ์ƒํ™ฉ์ด๋ผ๊ณ  ๊ฐ€์ •ํ•ด๋ณด๊ฒ ๋‹ค. a์™€ b๋Š” ์„œ๋กœ ์ž ์‹œ ๋ฉˆ์ถ”(Suspend)๋ฉด์„œ ๋‹ค๋ฅธ ์ฝ”๋ฃจํ‹ด์ด ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ฒŒ ์ž์›(A)์„ ์–‘๋ณดํ•˜๋Š” ์‹์ด๋‹ค. ์ด ์–‘๋ณด๋ฅผ ํ†ตํ•ด, ๊ฐ™์€ ์Šค๋ ˆ๋“œ์—์„œ ์—ฌ๋Ÿฌ ์ฝ”๋ฃจํ‹ด์ด ๋ฒˆ๊ฐˆ์•„ ๊ฐ€๋ฉฐ ์‹คํ–‰๋จ์œผ๋กœ์จ ๋ณ‘๋ ฌ์ ์ธ ๋™์‹œ ์‹คํ–‰์ฒ˜๋Ÿผ ๋ณด์ด๋Š” ๊ฒƒ์„ ์ฝ”๋ฃจํ‹ด์˜ ๋™์‹œ์„ฑ(Concurrency)์ด๋ผ๊ณ  ํ•œ๋‹ค. ์ด๋Š” ๋ฌผ๋ฆฌ์  ์Šค๋ ˆ๋“œ์˜ ์ง„์งœ ๋™์‹œ ์‹คํ–‰์ธ ๋ณ‘๋ ฌ์„ฑ(Parallelism)๊ณผ ๋Œ€๋น„๋œ๋‹ค.

 

ํ•˜๋‚˜์˜ ์ฝ”๋ฃจํ‹ด์„ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์— ํ•˜๋‚˜์”ฉ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ๋„ ํ•„์š”ํ•˜๋‹ค๋ฉด ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์Šค๋ ˆ๋“œ๊ฐ€ A, B, C ์ด 3๊ฐœ๊ฐ€ ์žˆ์„ ๋•Œ ํ”„๋กœ๊ทธ๋ž˜๋จธ๊ฐ€ CoroutineDispatcher๋ฅผ ์ด์šฉํ•ด A, B, C ๊ฐ๊ฐ์— ํ•˜๋‚˜์˜ ์ฝ”๋ฃจํ‹ด์„ ํ• ๋‹นํ•˜๋ฉด ๋œ๋‹ค (์ด๋Ÿฌ๋ฉด ์ฝ”๋ฃจํ‹ด์€ Concurrency๊ฐ€ ์•„๋‹ˆ๋ผ Parallelism์„ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋œ๋‹ค). ์ฝ”๋ฃจํ‹ด์€ ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” ๋…ผ๋ฆฌ์  ์Šค๋ ˆ๋“œ์ด์ง€๋งŒ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‹ค์ œ ๋ฌผ๋ฆฌ์  ์Šค๋ ˆ๋“œ๊นŒ์ง€ ๋ช…์‹œํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐํ•œ ๋„๊ตฌ์ธ ์…ˆ์ด๋‹ค.

 

#5 ์š”์•ฝ

๋ณ‘๋ ฌ ๊ตฌ์กฐ๋Š” ํ•„์—ฐ์ ์œผ๋กœ ้ž์ˆœ์ฐจ์ (้ž๋™๊ธฐ์ )์ด๊ณ , ๋”ฐ๋ผ์„œ Suspend๋ฅผ ์š”๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.