Coroutine Dispatcher๋?
Coroutine์ ์ค๋ ๋๋ก ๋ณด๋ด ์คํ์ํค๋ ์ญํ
- ์ค๋ ๋ / ์ค๋ ๋ ํ์ ๊ฐ์ง๋ฉฐ ์ฝ๋ฃจํด์ ์คํ ์์ฒญํ ์ค๋ ๋์์ ์ฝ๋ฃจํด์ด ์คํ๋๋๋ก ํจ
๋์ ๋ฐฉ์
์์ ์๊ฒ ์คํ ์์ฒญ๋ ์ฝ๋ฃจํด์ ์์ ๋๊ธฐ์ด์ ์ ์ฌํ ํ, ์ฌ์ฉํ ์ ์๋ ์ค๋ ๋๊ฐ ์๊ธฐ๋ฉด ์ค๋ ๋๋ก ๋ณด๋
- `CoroutineDispatcher` ๊ฐ์ฒด์ ์ฝ๋ฃจํด์ ์คํ์ด ์์ฒญ ๋จ
- [CoroutineDispatcher] ์คํ ์์ฒญ ๋ฐ์ ์ฝ๋ฃจํด์ ์์ ๋๊ธฐ์ด์ ์ ์ฌ
- [CoroutineDispatcher] ์ฌ์ฉํ ์ ์๋ ์ค๋ ๋๊ฐ ์๋์ง ํ์ธ
- ์๋ค๋ฉด, ์ฝ๋ฃจํด์ ํด๋น ์ค๋ ๋๋ก ๋ณด๋
- ์๋ค๋ฉด(๋ชจ๋ ์ค๋ ๋๊ฐ ์ฝ๋ฃจํด์ ์คํ์ค์ด๋ผ๋ฉด), ์์
๋๊ธฐ์ด์์ ๋๊ธฐํ๋๋ก ๋
- ์ค๋ ๋ ์ค ํ๋๊ฐ ์์ ๋ก์ ์ก์ ๋, ๋๊ธฐ์ด์ ์๋ ์ฝ๋ฃจํด์ ์ค๋ ๋๋ก ๋ณด๋
์ญํ
- ์ฝ๋ฃจํด์ ์คํ์ ๊ด๋ฆฌํ๋ ์ฃผ์ฒด
์ ํ๋ ๋์คํจ์ฒ์ ๋ฌด์ ํ ๋์คํจ์ฒ
์ ํ๋ ๋์คํจ์ฒ
- ์ฌ์ฉํ ์ ์๋ ์ค๋ ๋๊ฐ ์ ํ๋ ๋์คํจ์ฒ
- ์ผ๋ฐ์ ์ผ๋ก `CoroutineDispatcher` ๊ฐ์ฒด๋ณ๋ก ์ด๋ค ์์ ์ ์ฒ๋ฆฌํ ์ง ๋ฏธ๋ฆฌ ์ญํ ์ ๋ถ์ฌํ๊ณ , ์ญํ ์ ๋ง์ถฐ ์คํ์ ์์ฒญํ๋ ๊ฒ์ด ํจ์จ์ → ์ฃผ๋ก ์ฌ์ฉ๋จ
๋ฌด์ ํ ๋์คํจ์ฒ
- ์คํํ ์ ์๋ ์ค๋ ๋๊ฐ ์ ํ๋์ง ์์
- ์คํ ์์ฒญ๋ ์ฝ๋ฃจํด์ด ์๋ฌด ์ค๋ ๋์์๋ ์คํ๋๋ ๊ฒ์ด ์๋, ์คํ ์์ฒญ๋ ์ฝ๋ฃจํด์ด ์ด์ ์ฝ๋๊ฐ ์คํ๋๋ ์ค๋ ๋์์ ๊ณ์ ์คํ๋๋๋ก ํจ
์ ํ๋ ๋์คํจ์ฒ ์์ฑํ๊ธฐ
๋จ์ผ ์ค๋ ๋ ๋์คํจ์ฒ
- `Single-Thread Dispatcher`
- ์ฌ์ฉํ ์ ์๋ ์ค๋ ๋๊ฐ ํ๋์ธ Coroutine Dispatcher → ์ค๋ ๋ ํ: 1
val dispatcher: CoroutineDispatcher = newSingleThreadContext(name = "SingleThread")
- `name`: ๋์คํจ์ฒ์์ ๊ด๋ฆฌํ๋ ์ค๋ ๋์ ์ด๋ฆ
๋ฉํฐ ์ค๋ ๋ ๋์คํจ์ฒ
- `Multi-Thread Dispatcher`
- 2๊ฐ ์ด์์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ์ ์๋ CoroutineDispatcher
val multiThreadDispatcher: CoroutineDispatcher = newFixedThreadPoolContext(nThreads = 2, name = "MultiThread"))
- `nThreads` : ์ค๋ ๋ ๊ฐ์
- `name` : ์ค๋ ๋์ ์ด๋ฆ
- `MultiThread-1` , `MultiThread-2` ์ ๊ฐ์ด ‘-1’ ๋ถํฐ ์ซ์๊ฐ ํ๋์ฉ ์ฆ๊ฐํ๋ ํ์์ผ๋ก ์ด๋ฆ์ ๋ถ์
๐ ๋จ์ผ ์ค๋ ๋ ๋์คํจ์ฒ์ ๋ฉํฐ ์ค๋ ๋ ๋์คํจ์ฒ์ ๊ด๊ณ
- ๋ด๋ถ์ ์ผ๋ก `newFixedThreadPoolContext`๋ฅผ ์ฌ์ฉํ๊ณ ์์
- `newSingleThreadContext` ์ `newFixedThreadPoolContext` ๋ ๊ฐ์ ํจ์๋ผ๊ณ ๋ด๋ ๋ฌด๋ฐฉ
CoroutineDispatcher ์ฌ์ฉํ์ฌ ์ฝ๋ฃจํด ์คํํ๊ธฐ
launch์ ํ๋ผ๋ฏธํฐ๋ก ์ฌ์ฉํ๊ธฐ
๋จ์ผ ์ค๋ ๋ ๋์คํจ์ฒ ์ฌ์ฉ
fun main() = runBlocking {
val dispatcher = newSingleThreadContext(name = "SingleThread")
launch(context = dispatcher) {
println("[${Thread.currentThread().name}] ์คํ")
}
}
- ์์ ๋๊ธฐ์ด์ coroutine#2 ์ฝ๋ฃจํด์ ์ ์ฌํ ํ, ์ฝ๋ฃจํด์ SingleThread๋ก ๋ณด๋ด ์คํ์ํด
๋ฉํฐ ์ค๋ ๋ ๋์คํจ์ฒ ์ฌ์ฉ
fun multiThreadDispatcher() = runBlocking<Unit> {
val multiThreadDispatcher = newFixedThreadPoolContext(nThreads = 2, name = "MultiThread")
launch(context = multiThreadDispatcher) {
println("[${Thread.currentThread().name}] ์คํ")
}
launch(context = multiThreadDispatcher) {
println("[${Thread.currentThread().name}] ์คํ")
}
}
- CoroutineDispatcher ๊ฐ์ฒด ์์ฑ
- coroutine#2 ์คํ ์์ฒญ
- ์์ ๋๊ธฐ์ด์ coroutine#2 ์ ์ฌ ํ, MultiThread-1 ์ ํ ๋นํ์ฌ ์คํ
- coroutine#3 ์คํ ์์ฒญ
- ์์ ๋๊ธฐ์ด์ coroutine#3 ์ ์ฌ ํ, MultiThread-2 ์ ํ ๋นํ์ฌ ์คํ
โ ์คํ ํ๊ฒฝ์ ๋ฐ๋ผ ๊ฐ ์ฝ๋ฃจํด์ด ๋ค๋ฅธ ์๋๋ก ์ฒ๋ฆฌ๋ ์ ์๊ธฐ ๋๋ฌธ์, ์ค๋ ๋์ ์์๋ ์ฌ์ฉ๋๋ ์ค๋ ๋์ ์๋ ๋งค์ฐ ๋ถ๊ท์น์ ์ด๋ค.
CoroutineDispatcher ๊ตฌ์กฐํ
- ์ฝ๋ฃจํด์ ๊ตฌ์กฐํ: ์ฝ๋ฃจํด ๋ด๋ถ์์ ์๋ก์ด ์ฝ๋ฃจํด์ ์คํํ ์ ์๋ค.
- ์์ ์ฝ๋ฃจํด์ CoroutineDispatcher ๊ฐ์ฒด๊ฐ ์ค์ ๋์ด์์ง ์์ผ๋ฉด, ๋ถ๋ชจ ์ฝ๋ฃจํด์ CoroutineDispatcher ๊ฐ์ฒด๋ฅผ ์ฌ์ฉ
fun coroutineStructure() = runBlocking<Unit> {
val multiThreadDispatcher = newFixedThreadPoolContext(nThreads = 2, name = "MultiThread")
launch(multiThreadDispatcher) { // Parent Coroutine
println("[${Thread.currentThread().name}] ๋ถ๋ชจ ์ฝ๋ฃจํด ์คํ")
launch { // Child Coroutine
println("[${Thread.currentThread().name}] ์์ ์ฝ๋ฃจํด ์คํ")
}
launch { // Child Coroutine
println("[${Thread.currentThread().name}] ์์ ์ฝ๋ฃจํด ์คํ")
}
}
}
๋ถ๋ชจ์ ์์ ๋ชจ๋ ๊ฐ์ CoroutineDispatcher๋ฅผ ์ฌ์ฉํ๋ฏ๋ก MultiThread-1๊ณผ MultiThread-2๋ฅผ ๊ณต์ฉ์ผ๋ก ์ฌ์ฉ
๐ก ํน์ CoroutineDispatcher์์ ์ฌ๋ฌ ์์ ์ ์คํํด์ผ ํ๋ค๋ฉด, ๋ถ๋ชจ ์ฝ๋ฃจํด์ CoroutineDispatcher๋ฅผ ์ค์ ํ๊ณ , ๊ทธ ์๋์ ์์ ์ฝ๋ฃจํด์ ์ฌ๋ฌ๊ฐ ์์ฑํ์.
๋ฏธ๋ฆฌ ์ ์๋ CoroutineDispatcher
๋ฌธ์ ์
- `newFixedThreadPoolContext` ํจ์๋ฅผ ์ฌ์ฉํ์ฌ CoroutineDispatcher๋ฅผ ๋ง๋ค๋ฉด, ํน์ CoroutineDispatcher ๊ฐ์ฒด์์๋ง ์ฌ์ฉ๋๋ ์ค๋ ๋ ํ์ด ์์ฑ → ์ค๋ ๋ ํ์ ์ํ ์ค๋ ๋์ ์๊ฐ ๋๋ฌด ๋ง๊ฑฐ๋ ์ ๊ฒ ์์ฑ๋์ด ๋นํจ์จ์ ์ธ ๋์ ์ ๋ฐ
- ์ฌ๋ฌ ๊ฐ๋ฐ์๊ฐ ์์ ํ ๊ฒฝ์ฐ, ์ด๋ฏธ ๋ฉ๋ชจ๋ฆฌ ์์ ์์์๋ ํด๋น ๊ฐ์ฒด์ ์กด์ฌ๋ฅผ ๋ชฐ๋ผ ๋ค์ CoroutineDispatcher ๊ฐ์ฒด๋ฅผ ๋ง๋๋ ๋ฆฌ์์ค ๋ญ๋น ๋ฐ์ ๊ฐ๋ฅ
ํด๊ฒฐ
๐ ๋ฏธ๋ฆฌ ์ ์๋ CoroutineDispatcher์ ๋ชฉ๋ก์ ์ ๊ณต
- `Dispatchers.IO`
- `Dispatchers.Default`
- `Dispatchers.Main`
Dispatchers.IO
- ๋คํธ์ํฌ ์์ฒญ์ด๋ ํ์ผ ์ ์ถ๋ ฅ๋ฑ์ IO ์์ ์ ์ํ CoroutineDispatcher
- ์ต๋๋ก ์ฌ์ฉํ ์ ์๋ ์ค๋ ๋ ์: JVM์์ ์ฌ์ฉ ๊ฐ๋ฅํ ํ๋ก์ธ์์ ์์ 64 ์ค ํฐ ๊ฐ
- ๐์ฌ๋ฌ ์ ์ถ๋ ฅ ์์ ์ ๋์์ ์ํํ ์ ์์๐
fun dispatchersIO() = runBlocking<Unit> {
launch(Dispatchers.IO) {
println("[${Thread.currentThread().name}] ์ฝ๋ฃจํด ์คํ")
}
}
- `DefaultDispatcher-worker : ์ฝ๋ฃจํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ์ ๊ณตํ๋ ๊ณต์ ์ค๋ ๋ํ์ ์ํ ์ค๋ ๋
- Dispatchers.IO๋ ๊ณต์ ์ค๋ ๋ํ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ๊ตฌํ๋์ด ์์
Dispatchers.Default
- CPU๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ ์ฐ์ฐ ์์ ์ ์ํ CoroutineDispatcher
fun dispatchersDefault() = runBlocking<Unit> {
launch(Dispatchers.Default) {
println("[${Thread.currentThread().name}] ์ฝ๋ฃจํด ์คํ")
}
}
๐ ์ ์ถ๋ ฅ ์์ ๊ณผ CPU ๋ฐ์ด๋ ์์
- ์ ์ถ๋ ฅ ์์ : ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ๋ฐ์ ๋ ๊น์ง ์ค๋ ๋๋ฅผ ์ฌ์ฉํ์ง ์์
- CPU ๋ฐ์ด๋ ์์ : ์์ ์ ํ๋ ๋์ ์ค๋ ๋๋ฅผ ์ง์์ ์ผ๋ก ์ฌ์ฉ
I/O ์์ | CPU ๋ฐ์ด๋ ์์ | |
์ค๋ ๋ ๊ธฐ๋ฐ ์์ ์ | ๋๋ฆผ | ๋น์ท |
์ฝ๋ฃจํด ์ฌ์ฉ ์ | ๋น ๋ฆ (๋๊ธฐํ๋ ๋์ ํด๋น ์ค๋ ๋์์ ๋ค๋ฅธ ์ ์ถ๋ ฅ ์์ ์ ๋์์ ์งํ) |
limitedParallelism
๋ฌธ์ ์
์ฌ์ฉ์ด ๋ฌด๊ฒ๊ณ ์ค๋๊ฑธ๋ฆฌ๋ ์ฐ์ฐ ์ฒ๋ฆฌ๋ฅผ ์ํด `Dispatchers.Default` ์ ๋ชจ๋ ์ค๋ ๋๊ฐ ์ฌ์ฉ๋ ์ ์์
`Dispatchers.Default` ๋ฅผ ์ฌ์ฉํ๋ ๋ค๋ฅธ ์ฐ์ฐ์ด ์คํ๋์ง ๋ชปํจ
ํด๊ฒฐ
`limitedParallelism` : ์ผ๋ถ ์ค๋ ๋๋ง ์ฌ์ฉํ์ฌ ํน์ ์ฐ์ฐ์ ์คํํ ์ ์๋๋ก ํ๋ ํจ์
fun limitedParallelism() = runBlocking<Unit> {
launch(Dispatchers.Default.limitedParallelism(2)) {
repeat(10) {
launch {
println("[${Thread.currentThread().name}] ์ฝ๋ฃจํด ์คํ")
}
}
}
}
- Dispatchers.Default ์ ์ฌ๋ฌ ์ค๋ ๋ ์ค 2๊ฐ์ ์ค๋ ๋๋ง์ ์ฌ์ฉ
๊ณต์ ์ค๋ ๋ํ
- ์ฝ๋ฃจํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ค๋ ๋์ ์์ฑ๊ณผ ๊ด๋ฆฌ๋ฅผ ํจ์จ์ ์ผ๋ก ํ ์ ์๋๋ก ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฒจ์ ๊ณต์ ์ค๋ ๋ํ์ ์ ๊ณต
- ๊ณต์ ์ค๋ ๋ํ์์๋ ์ค๋ ๋๋ฅผ ๋ฌด์ ํ์ผ๋ก ์์ฑ ๊ฐ๋ฅ
- ์ฝ๋ฃจํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์ค๋ ๋๋ฅผ ์์ฑํ๊ณ ์ฌ์ฉํ๋๋ก ํ๋ API ์ ๊ณต
- `newFixedThreadPoolContext` ํจ์๋ก ๋ง๋ค์ด์ง๋ ๋์คํจ์ฒ๋ ์์ ๋ง ์ฌ์ฉํ ์ ์๋ ์ ์ฉ ์ค๋ ๋ํ ์์ฑ
- `Dispatchers.IO`์ `Dispatchers.Default` ๋ ๊ณต์ ์ค๋ ๋ํ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉ
Dispatchers.Main
- UI๊ฐ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋ฉ์ธ ์ค๋ ๋์ ์ฌ์ฉ์ ์ํด ์ฌ์ฉ๋จ
- ๋ณ๋์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ(kotlinx-coroutines-android ๋ฑ)์ ์ถ๊ฐํด์ผ ์ฌ์ฉ ๊ฐ๋ฅ
http://www.acornpub.co.kr/book/kotlin-coroutines
์ฝํ๋ฆฐ ์ฝ๋ฃจํด์ ์ ์
๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ด๋ ต๊ฒ ๋๋ผ๋ ๋น๋๊ธฐ ํ๋ก๊ทธ๋๋ฐ์ ๋ค์ํ ์๊ฐ์ ์๋ฃ์ ์ค๋ช ์ ํตํด ๋๊ตฌ๋ ์ฝ๊ฒ ์ดํดํ ์ ์๋๋ก ์ฐ์ธ ์ฑ ์ด๋ค.
www.acornpub.co.kr
๐ํ๊ธฐ๐
Spring Boot - Kotlin ์ฌ์ฉํ๋ ํ๊ฒฝ์์ ์ฝ๋ฃจํด์ ๋ํ ๋ ๊น์ ์ง์์ด ํ์ํด ์ฐพ๋ค ๋ฐ๊ฒฌํ ์ฑ .
ํ๊ตญ์ธ ์ ์ ๋ถ์ด์ด์ ๊ทธ๋ฐ์ง ์ ๋ฐ์ ์ผ๋ก ์ดํดํ๊ธฐ ๊ต์ฅํ ์ฝ๊ฒ ๋์ด์๊ณ ,
๊ธฐ์กด ์ฝํ๋ฆฐ ์ฑ ์์๋ ์ฝ๊ฒ ๋ค๋ค์ง์ง ์๋ ๋ ๋ฅํ ์ฝ๋ฃจํด ๊ธฐ๋ฅ๊น์ง ์ ์ ์์.
(์ง๊ธ๊น์ง ์ฝ์ ๊ธฐ์ ์ ์ค ์ค๋ฌด์์ ๊ฐ์ฅ ์ ์ฐ๊ณ ์๋ ์ฑ ...๊ฐ์ฅ ์ ์ ์ฝํ ์ฑ ...๐)
SpringBoot-Kotlin ํ๊ฒฝ์์ ์ฝ๋ฃจํด์ ๋ ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด ์ ๋ง ๊ฐ์ถ ํ์ ํ์ ๐๐ฅ๐๐ฅ๐๐ฅ๐๐ฅ๐๐ฅ