[kotlin/μ½νλ¦° μ½λ£¨ν΄μ μ μ] 3μ₯. CoroutineDispatcher
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 νκ²½μμ μ½λ£¨ν΄μ λ 곡λΆνκ³ μΆλ€λ©΄ μ λ§ κ°μΆ νμ νμ ππ₯ππ₯ππ₯ππ₯ππ₯