03
29

https://kotlinlang.org/docs/coroutine-context-and-dispatchers.html

 

Coroutine context and dispatchers | Kotlin

 

kotlinlang.org

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

 

์ฝ”๋ฃจํ‹ด์—์„œ ์‚ฌ์šฉํ•˜๋Š” context๋Š” ๋Œ€ํ‘œ์ ์œผ๋กœ CoroutineContext ํƒ€์ž…์ด ์žˆ๋‹ค. ์ด๋ฒˆ ํŽ˜์ด์ง€์—์„œ๋Š” ์ด์ „์— ๋ดค๋˜ Job ๊ฐ์ฒด์™€ Dispatcher๋ฅผ ์‚ดํŽด๋ณด๊ฒ ๋‹ค.

 

Dispatchers and threads

coroutine context์—๋Š” coroutine dispatcher๋„ ํฌํ•จ๋˜๋Š”๋ฐ ํ•ด๋‹น ์ฝ”๋ฃจํ‹ด์„ ์‹คํ–‰ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์“ฐ๋ ˆ๋“œ๋‹ค. dispatcher๋กœ ํŠน์ • ์“ฐ๋ ˆ๋“œ๋ฅผ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฝ”๋ฃจํ‹ด์˜ ์‹คํ–‰์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค. dispatch์˜ ๋œป์ด ๋ณด๋‚ด๋‹ค๋ผ๋Š” ์˜๋ฏธ์ธ๋ฐ ์“ฐ๋ ˆ๋“œ ํ’€๋กœ ๋ณด๋‚ด๊ฑฐ๋‚˜ ์•„๋‹ˆ๋ฉด ์•ˆ๋ณด๋‚ด๊ณ  ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์ดํ•ดํ–ˆ๋‹ค.

 

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

    launch { // context of the parent, main runBlocking coroutine
        println("main runBlocking      : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
        println("Unconfined            : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Default) { // will get dispatched to DefaultDispatcher 
        println("Default               : I'm working in thread ${Thread.currentThread().name}")
    }
    launch(newSingleThreadContext("MyOwnThread")) { // will get its own new thread
        println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
    }

์ด๊ฑธ ์‹คํ–‰ํ•ด๋ณด๋ฉด 1,2,3,4๊ฐ€ 2,3,1,4 ์ˆœ์„œ๋Œ€๋กœ ์ถœ๋ ฅ๋œ๋‹ค. ๋””์ŠคํŒจ์ฒ˜๋ฅผ ์ง€์ •ํ•˜์ง€์•Š์œผ๋ฉด ๋ถ€๋ชจ ์ฝ”๋ฃจํ‹ด์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ฐ›๋Š”๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์ œ์ผ ๋ฐ”๊นฅ์— runBlocking(main ์“ฐ๋ ˆ๋“œ์—์„œ ๋Œ์•„๊ฐ)์ด ์žˆ์œผ๋‹ˆ 1๋ฒˆ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฉ”์ธ์ด๋‹ค. 

 

๋””ํดํŠธ ๋””์ŠคํŒจ์ฒ˜๋Š” JVM์— ์žˆ๋Š” ๊ณต์œ  ์“ฐ๋ ˆ๋“œ ํ’€์—์„œ ๋Œ์•„๊ฐ„๋‹ค. ๋””์ŠคํŒจ์ฒ˜์— ๋‹ค๋ฅธ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ง€์ •๋˜์ง€์•Š์€ ๊ฒฝ์šฐ ์‚ฌ์šฉ๋œ๋‹ค. ์ด ๋””์ŠคํŒจ์ฒ˜์—์„œ ์‚ฌ์šฉํ•  ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ์ˆ˜์ค€์€ CPU์ฝ”์–ด ๊ฐœ์ˆ˜๋ฅผ ๋”ฐ๋ผ๊ฐ€์ง€๋งŒ ์ตœ์†Œ 2๊ฐœ๋กœ ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.

 

๋งˆ์ง€๋ง‰ ์ฝ”๋ฃจํ‹ด์—์„œ ๋””์ŠคํŒจ์ฒ˜๋Š” ์ฝ”๋ฃจํ‹ด์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ•˜๋‚˜ ์ƒ์„ฑํ•œ ๊ฒƒ์ด๋‹ค. ์ „์šฉ ์“ฐ๋ ˆ๋“œ๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ์€ ๋ฆฌ์†Œ์Šค๋ฅผ ๋งŽ์ด ์ฐจ์ง€ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ๋กœ๋Š” close๋กœ ํ•ด๋‹น ์ฝ”๋ฃจํ‹ด ๋””์ŠคํŒจ์ฒ˜๋ฅผ ๋‹ซ์•„์ฃผ๊ฑฐ๋‚˜ ์ตœ์ƒ์œ„ ๋ณ€์ˆ˜๋กœ ์ง€์ •ํ•ด ์•ฑ ์ „์ฒด์—์„œ ์‚ฌ์šฉํ•˜๊ฒŒ ํ•ด์•ผํ•œ๋‹ค.

CoroutineDispatcher

๋ชจ๋“  ๋””์ŠคํŒจ์ฒ˜๊ฐ€ ํ™•์žฅํ•ด์„œ ์‚ฌ์šฉํ•˜๋Š” ์ถ”์ƒํด๋ž˜์Šค์ด๋‹ค. kotlinx.coroutines์— ์žˆ๋Š” ๋””์ŠคํŒจ์ฒ˜ ๋ชฉ๋ก์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

Dispatchers.Default:

๋””์ŠคํŒจ์ฒ˜์— ๋”ฐ๋กœ context๊ฐ€ ์ง€์ •๋˜์ง€์•Š์œผ๋ฉด ์ด๊ฒŒ ์‚ฌ์šฉ๋œ๋‹ค. ๊ณต์œ  ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์“ฐ๋ ˆ๋“œ์˜ ๊ณต์šฉ ํ’€์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— CPU๋ฆฌ์†Œ์Šค๊ฐ€ ๋งŽ์ด ํ•„์š”ํ•œ ์ž‘์—…์— ์ ํ•ฉํ•˜๋‹ค.

Dispatchers.IO:

์š”์ฒญํ•  ๋•Œ ์ƒ๊ธฐ๋Š” ์“ฐ๋ ˆ๋“œ์˜ ๊ณต์œ  ํ’€์„ ์‚ฌ์šฉํ•˜๊ณ  ํŒŒ์ผ์ž…์ถœ๋ ฅ, ์†Œ์ผ“์ž…์ถœ๋ ฅ ์ฐจ๋‹จ๊ณผ ๊ฐ™์€ ์ž‘์—…์— ์‚ฌ์šฉ๋œ๋‹ค. ์ด๊ฑธ Offloading์ด๋ผ๊ณ  ํ•˜๋Š”๋ฐ CPU๊ฐ€ TCP/IP ํ”„๋กœ์„ธ์‹ฑํ•˜๋Š” ๊ฑธ ๋ง‰์•„์„œ ์„ฑ๋Šฅ์„ ์˜ฌ๋ฆฌ๋Š” ์ž‘์—…์ด๋‹ค.

Dispatchers.Unconfined:

์ฝ”๋ฃจํ‹ด ๋นŒ๋”๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š” ์ฒซ ์ง€์ ๊นŒ์ง€ ์ฝ”๋ฃจํ‹ด์„ ์‹คํ–‰ํ•œ๋‹ค. ์ค‘๋‹จ๋œ ์ฝ”๋ฃจํ‹ด์€ ํ•ด๋‹น ์ค‘๋‹จ ํ•จ์ˆ˜์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์“ฐ๋ ˆ๋“œ์—์„œ ์žฌ์‹œ์ž‘๋œ๋‹ค. ๋ฐ‘์— ์กฐ๊ธˆ ๋” ์ž์„ธํžˆ ์ •๋ฆฌํ•˜์˜€๋‹ค.

 

private ์“ฐ๋ ˆ๋“œ ํ’€์€ newSingleThreadContext, newFixedThreadPoolContext๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค. 

Unconfined Dispatcher vs Confined Dispatcher

unconfine์€ ์ œํ•œ์ด ์—†๋Š”์ด๋ผ๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„๋‹ค. unconfined ๋””์ŠคํŒจ์ฒ˜๋Š” ์ฝ”๋ฃจํ‹ด์„ ํ˜ธ์ถœํ•œ ์“ฐ๋ ˆ๋“œ์—์„œ ์‹œ์ž‘ํ•ด ์ฒซ suspend์ง€์ ๊นŒ์ง€ ์‹คํ–‰ํ•œ๋‹ค. ์ง€์—ฐ์ด ๋๋‚˜๋ฉด ์ฝ”๋ฃจํ‹ด์„ ์žฌ๊ฐœํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์ž‘์—…์€ ์ค‘๊ฐ„์— ๋ฉˆ์ถ”๊ธฐ ๋•Œ๋ฌธ์— cpu time์„ ์†Œ๋น„ํ•˜๊ฑฐ๋‚˜ ui update๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ์ž‘์—…์—๋Š” ์ ์ ˆํ•˜์ง€์•Š๋‹ค. unconfined ๋””์ŠคํŒจ์ฒ˜๋„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์™ธ๋ถ€ ์ฝ”๋ฃจํ‹ด์Šค์ฝ”ํ”„๋ฅผ ์ƒ์†๋ฐ›์•„ ์‚ฌ์šฉํ•œ๋‹ค. ๊ทธ์ค‘ runBlocking์€ ํŠนํžˆ ํ˜ธ์ถœ์šฉ ์Šค๋ ˆ๋“œ๋กœ ์ œํ•œ๋˜๋Š”๋ฐ ์ด๊ฑธ ์ƒ์†๋ฐ›์€ unconfined ๋””์ŠคํŒจ์ฒ˜๋Š” FIFO ์Šค์ผ€์ค„๋ง์ฒ˜๋Ÿผ ์‚ฌ์šฉ๋œ๋‹ค๊ณ  ํ•œ๋‹ค.

launch(Dispatchers.Unconfined) { // not confined -- will work with main thread
    println("Unconfined      : I'm working in thread ${Thread.currentThread().name}")
    delay(900)
    println("Unconfined      : After delay in thread ${Thread.currentThread().name}")
}
launch { // context of the parent, main runBlocking coroutine
    println("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
    delay(1000)
    println("main runBlocking: After delay in thread ${Thread.currentThread().name}")
}

ํ”„๋ฆฐํŠธ๋ฌธ์„ 1,2,3,4๋ผ๊ณ  ํ• ๋•Œ 1,3,2,4๋ผ๊ณ  ๋Œ€๋‹ตํ•˜๋Š”๊ฒŒ ์ผ๋ฐ˜์ ์ด๋‹ค. ์ด๊ฑด unconfined๊ฐ€ ์—†์–ด๋„ ๋‹น์—ฐํ•œ ๊ฒฐ๊ณผ์ธ๋ฐ ๋‹ค๋ฅธ ์ ์€ unconfined ๋””์ŠคํŒจ์ฒ˜์˜ ๋‘๋ฒˆ์งธ ํ”„๋ฆฐํŠธ๋ฌธ์ด๋‹ค. 

Unconfined      : After delay in thread kotlinx.coroutines.DefaultExecutor

์ด๋Ÿฐ ๋ฉ”์‹œ์ง€๊ฐ€ ๋‚˜์˜จ๋‹ค. ์ฒซ๋ฒˆ์งธ ํ”„๋ฆฐํŠธ๋ฌธ์„ ์ถœ๋ ฅํ•  ๋•Œ ์‚ฌ์šฉํ•œ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€์•Š๊ณ  ์žˆ๋Š” ๋ชจ์Šต์„ ๋ณด์—ฌ์ฃผ๋Š”๋ฐ ์ด๊ฑด delay๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋ณธ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿผ ์›๋ž˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€์•Š๋Š”๋‹ค๋Š” ๋ง์ธ๋ฐ unconfined dispatcher๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชฉ์ ์€ ์ผ๋ถ€์ž‘์—… ์ฆ‰์‹œ์ˆ˜ํ–‰์ด๋‹ค. ๋”œ๋ ˆ์ด ํ•จ์ˆ˜๋ฅผ ๊ฑฐ์น˜๋ฉด์„œ suspend๊ฑธ๋ฆฐ์ˆœ๊ฐ„ ์™ธ๋ถ€ ์ฝ”๋ฃจํ‹ด์„ ์žฌ๊ฐœํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋‚˜์ค‘์— ์‹คํ–‰ํ•  ์ž‘์—…์ด ์žˆ๋Š” ์ฝ”๋ฃจํ‹ด์—์„œ๋Š” ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

Job in the context

job๋„ ์ปจํ…์ŠคํŠธ์˜ ์ผ๋ถ€์ธ๋ฐ ์•„๋ž˜์™€ ๊ฐ™์ด ํ•ด๋‹น job์˜ context๋ฅผ ์ถ”์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

println("My job is ${coroutineContext[Job]}")

์—ฌ๊ธฐ์„œ ์ƒˆ๋กญ๊ฒŒ ์•Œ๊ฒŒ๋œ ์‚ฌ์‹ค์ธ๋ฐ isActive ํ”„๋กœํผํ‹ฐ๊ฐ€ coroutineContext[Job]?.isActive == true์˜ ๋‹จ์ถ•์–ด์ด๋‹ค. ํ˜„์žฌ ์ฝ”๋ฃจํ‹ด์„ ์ถ”์ถœํ•ด isActive๊ฐ€ true์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์„ ์ค„์—ฌ๋‘” ๊ฒƒ์ด๋‹ค.

Children of a coroutine

์ฝ”๋ฃจํ‹ด์ด ๋‹ค๋ฅธ ์ฝ”๋ฃจํ‹ด ์•ˆ์—์„œ ์‹คํ–‰๋˜๋ฉด ์™ธ๋ถ€ ์ฝ”๋ฃจํ‹ด์˜ context๋ฅผ ์ƒ์†๋ฐ›๋Š”๋‹ค. ๊ทธ ๋ง์€ ๋‚ด๋ถ€ ์ฝ”๋ฃจํ‹ด์˜ Job์ด ์™ธ๋ถ€ ์ฝ”๋ฃจํ‹ด Job์˜ ์ž์‹์ด ๋œ๋‹ค๋Š” ๋ง์ด๋‹ค. structured concurrency์— ๊ทผ๊ฑฐํ•ด ๋ถ€๋ชจ ์ฝ”๋ฃจํ‹ด์ด ์ทจ์†Œ๋˜๋ฉด ๊ทธ๋Œ€๋กœ ์ž์‹๊นŒ์ง€ ์ „ํŒŒ๋˜์–ด ๋‹ค ์ทจ์†Œ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์ด ์ „ํŒŒํ˜•์ƒ์€ override ์ƒํ™ฉ์—์„œ๋Š” ์ ์šฉ๋˜์ง€์•Š๋Š”๋‹ค.

 

๋‚ด๋ถ€ ์ฝ”๋ฃจํ‹ด์—์„œ ๋ช…์‹œ์ ์œผ๋กœ ๋‹ค๋ฅธ ์Šค์ฝ”ํ”„๋ฅผ ์ง€์ •ํ•  ๊ฒฝ์šฐ ๋ถ€๋ชจ ์Šค์ฝ”ํ”„๋ฅผ ์ƒ์†๋ฐ›์ง€ ์•Š๋Š”๋‹ค. ๋‹ค๋ฅธ ์˜ˆ๋กœ๋Š” ์•„๋ž˜ ์ฝ”๋“œ๊ฐ€ ์žˆ๋‹ค.

val request = launch {
    launch(Job()) { 
        println("job1: I run in my own Job and execute independently!") //1
        delay(1000)
        println("job1: I am not affected by cancellation of the request") //2
    }
    launch {
        delay(100)
        println("job2: I am a child of the request coroutine") //3
        delay(1000)
        println("job2: I will not execute this line if my parent request is cancelled") //4
    }
}
delay(500)
request.cancel()
println("main: Who has survived request cancellation?") //5
delay(1000)

lauch ์•ˆ์— ์žˆ๋Š” Job์€ ๋‹ค๋ฅธ ๊ณณ์—์„œ ์˜จ Job์ด๋‹ค. ์ด๊ฑธ๋ฐ›๋Š” ์ˆœ๊ฐ„ ์™ธ๋ถ€ ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„๋ฅผ ์ƒ์† ๋ฐ›์ง€์•Š๋Š”๋‹ค. 1,2,3,4,5์˜ ์ถœ๋ ฅ ์ˆœ์„œ๋Š” 1,3,5,2๋‹ค.

1,2 ๊ฐ€ ๋“ค์–ด์žˆ๋Š” ์ฝ”๋ฃจํ‹ด์€ ์™ธ๋ถ€์˜ Job์„ ์ƒ์†๋ฐ›์•˜๊ธฐ ๋•Œ๋ฌธ์— request์— ๋“ค์–ด๊ฐ€๋Š” ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„์™€๋Š” ๋…๋ฆฝ์ ์ด๋‹ค. ๋”ฐ๋ผ์„œ cancel์˜ ์˜ํ–ฅ์ด ์—†๋‹ค. 

Parental Resposibilities

๋ถ€๋ชจ ์ฝ”๋ฃจํ‹ด์€ ์ž์‹ ์ฝ”๋ฃจํ‹ด์ด ๋๋‚  ๋•Œ ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. ์ด๊ฒƒ ์—ญ์‹œ ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ์— ๋”ฐ๋ฅธ ๊ทœ์น™์ผ ๊ฒƒ์ด๋‹ค. 

fun main() = runBlocking<Unit> {
    val request = launch {
        repeat(3) { i ->
            launch  {
                delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
                println("Coroutine $i is done")
            }
        }
        println("request: I'm done and I don't explicitly join my children that are still active")
    }
    request.join()
    println("Now processing of the request is complete")
}

์—ฌ๊ธฐ์„œ ๋งจ ๋งˆ์ง€๋ง‰ ์ถœ๋ ฅ๋ฌธ์€ Now~๋ฌธ์žฅ์ด๋‹ค. join()์€ request๊ฐ€ ๋๋‚˜๋Š” ๊ฒƒ์„ ๊ธฐ๋‹ค๋ ธ๋‹ค๊ฐ€ ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— request์˜ ์ž์‹ ์ฝ”๋ฃจํ‹ด์ด ๋ชจ๋‘ ์‹คํ–‰๋˜๊ณ ๋‚˜์„œ join()์„ ์ง„ํ–‰ํ•œ๋‹ค.

Combining context elements

launch(Dispatchers.Default + CoroutineName("๋งŒ๋‘")) {
    println("I'm working in thread ${Thread.currentThread().name}")
}

//์ถœ๋ ฅ
I'm working in thread DefaultDispatcher-worker-1 @๋งŒ๋‘#2

CoroutineName์€ ๋””๋ฒ„๊น…์šฉ context๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ๋””๋ฒ„๊ทธ ๋กœ๊ทธ์— ํ•ด๋‹น ์ด๋ฆ„์„ ๊ฐ–๊ณ  ๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋œ๋‹ค. 

 

Coroutine scope - Class์—์„œ ์“ด๋‹ค๋ฉด

์ฝ”๋ฃจํ‹ด์Šค์ฝ”ํ”„ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์•กํ‹ฐ๋น„ํ‹ฐ์— ์ œํ•œํ•  ์ˆ˜ ์žˆ๋‹ค. CoroutineScope(), MainScope()๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐฐ์ •ํ•ด ์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„๋ฅผ ์•กํ‹ฐ๋น„ํ‹ฐ ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. MainScope์— ์ฃผ๋ชฉํ•ด์•ผํ•˜๋Š”๋ฐ Dispathcers.Main์„ ๊ธฐ๋ณธ ๋””์ŠคํŒจ์ฒ˜๋กœ ์‚ฌ์šฉํ•˜๊ณ  UI๋ฅผ ๊ทธ๋ฆฌ๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์Šค์ฝ”ํ”„์ด๊ธฐ๋•Œ๋ฌธ์ด๋‹ค.

 

์ฝ”๋ฃจํ‹ด ์Šค์ฝ”ํ”„๋ฅผ ๋งŒ๋“ค๊ณ  ๋‚˜๋ฉด, ์ด์ œ ์Šค์ฝ”ํ”„์ธ์Šคํ„ด์Šค.launch{ }์™€ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ์ฝ”๋ฃจํ‹ด์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. 

    fun doSomething() {
        // launch ten coroutines for a demo, each working for a different time
        repeat(10) { i ->
            mainScope.launch {
                delay((i + 1) * 200L) // variable delay 200ms, 400ms, ... etc
                println("Coroutine $i is done")
            }
        }
    }

์ด๋ ‡๊ฒŒ ๋งŒ๋“  ํด๋ž˜์Šค ๋ฉ”์„œ๋“œ๋Š” ์•กํ‹ฐ๋น„ํ‹ฐ ์ธ์Šคํ„ด์Šค๋ฅผ ์ด์šฉํ•ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์•กํ‹ฐ๋น„ํ‹ฐ ์ธ์Šคํ„ด์Šค๋ฅผ destroyํ•˜๋ฉด ์ธ์Šคํ„ด์Šค ๋‚ด๋ถ€ ์ฝ”๋ฃจํ‹ด๋„ cancel๋œ๋‹ค.

 

 

"๋Œ“๊ธ€, ๊ณต๊ฐ ๋ฒ„ํŠผ ํ•œ ๋ฒˆ์”ฉ ๋ˆ„๋ฅด๊ณ  ๊ฐ€์ฃผ์‹œ๋ฉด ํฐ ํž˜์ด ๋ฉ๋‹ˆ๋‹ค"
๋ฐ˜์‘ํ˜•
COMMENT