๐ก RxJava์์์ ์ค์ผ์ค๋ฌ์ ๋น์ทํ ๊ธฐ๋ฅ์ ํ๋ ์ฝ๋ฃจํด ๋์คํจ์ฒ์ ๋ํ์ฌ ํ์ตํ์์ต๋๋ค.
CoroutineDispatcher
- ์ฝํฌ๋ฆฐ ๋์คํจ์ฒ๋ ์ฝ๋ฃจํด์ ์ค๋ ๋๋ก ๋ณด๋ด๋ ์ญํ ์ ํฉ๋๋ค.
- ๋ชจ๋ ์์ ์ ์ค๋ ๋ ์์์ ์คํ๋ผ์ผ ํ๊ณ , ์ฝ๋ฃจํด ๋ํ ์์ ์ด๋ฏ๋ก ์ค๋ ๋ ์์์๋ง ์คํ๋ ์ ์์ต๋๋ค.
- ์ฐ๋ฆฌ๊ฐ ์ฝ๋ฃจํด์ ๋ง๋ค์ด CoroutineDispatcher๋ก ์ฝ๋ฃจํด ์คํ์ ์์ฒญํ๋ฉด, CoroutineDispatcher๋ ์์ ์ด ์ฌ์ฉํ ์ ์๋ ์ค๋ ๋ํ์ ์ค๋ ๋ ์ค ํ๋์ ์ฝ๋ฃจํด์ ๋ณด๋ ๋๋ค.
๊ธฐ๋ณธ ๋์คํจ์ฒ
- ๋์คํจ์ฒ๋ฅผ ์ค์ ํ์ง ์์ผ๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก Dispatchers.Default๊ฐ ์ค์ ๋ฉ๋๋ค.
- CPU๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ ์์ ์์ ์คํํฉ๋๋ค.
- ์ด ๋์คํจ์ฒ๋ ์ฝ๋๊ฐ ์คํ๋๋ ์ปดํจํฐ์ CPU ๊ฐ์์ ๋์ผํ ์(์ต์ 2๊ฐ ์ด์)์ ์ค๋ ๋ ํ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
suspend fun main() = coroutineScope {
repeat(1000) {
launch { //**Dispatchers.Default**
val threadName = Thread.currentThread().name
println("Running on thread: $threadName")
}
} ****
}
// Running on thread: DefaultDispathcer-worker-1
// Running on thread: DefaultDispathcer-worker-2
// ....
- runBlocking์ ๋์คํจ์ฒ๊ฐ ์ค์ ๋์ง ์์ผ๋ฉด ์์ ๋ง์ ๋์คํจ์ฒ๋ฅผ ์ฌ์ฉํ๋ฏ๋ก Dispatchers.Default๋ฅผ ์๋์ผ๋ก ์ ํํ์ง ์์ต๋๋ค.
- ์ ์์๋ coroutineScope ๋์ ์ runBlocking์ ์ฌ์ฉํ๋ฉด ๋ชจ๋ ์ฝ๋ฃจํด์ main์์ ์คํ๋ฉ๋๋ค.
๋์คํจ์ฒ ์ ํํ๊ธฐ
- limitedParallelism์ ์ฌ์ฉํด์ ๋์คํจ์ฒ๊ฐ ๊ฐ์ ์ค๋ ๋ ํ์ ์ฌ์ฉํ์ง๋ง ๊ฐ์ ์๊ฐ์ ํน์ ์ ์ด์์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ์ง ๋ชปํ๋๋ก ์ ํํ ์ ์์ต๋๋ค.
private val dispatcher = Dispatchers
.Default
.limitedParallelism(5)
- limitedParallelism์ kotlinx.coroutines 1.6 ๋ฒ์ ์์ ๋์ ๋์์ต๋๋ค.
๋ฉ์ธ ๋์คํจ์ฒ
- Dispatchers.Main์ ํตํด์ ๋ฉ์ธ ์ค๋ ๋์์ ์ฝ๋ฃจํด์ ์คํํ ์ ์์ต๋๋ค.
- UI์ ์ํธ์์ฉํ๋ ์์ ์ ์คํํ๊ธฐ ์ํด์ ์ฌ์ฉ๋ฉ๋๋ค.
- ๋ฉ์ธ ์ค๋ ๋๊ฐ ๋ธ๋กํน๋๋ฉด ์ ์ฒด ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฉ์ถ๋ฏ๋ก, ์กฐ์ฌ์ค๋ฝ๊ฒ ๋ค๋ค์ผ ํฉ๋๋ค.
- ๋จ์ ํ ์คํธ ์ kotlinx-coroutines-test์์ Dispatchers.setMain(dispatcher)๋ก ๋์คํจ์ฒ๋ฅผ ์ค์ ํ ์ ์์ต๋๋ค.
- ๋ธ๋กํน ๋์ ์ค๋จํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๊ณ ๋ณต์กํ ์ฐ์ฐ์ ํ์ง ์๋๋ค๋ฉด Dispatchers.Main์ผ๋ก ๊ธฐ๋ณธ ๋์คํจ์ฒ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
IO ๋์คํจ์ฒ
- ๋์คํฌ ๋๋ ๋คํธ์ํฌ I/O ์์ ์ ์คํํ๋๋ฐ ์ต์ ํ๋์ด ์์ต๋๋ค.
- IO ๋์คํจ์ฒ๋ ์๊ฐ์ด ์ค๋ ๊ฑธ๋ฆฌ๋ ์์ ์ด๋ ๋ธ๋กํน ํจ์๊ฐ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋ ํ์ํฉ๋๋ค.
- ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ฉ์ถ๊ฒ ํ ์๋ ์๊ธฐ ๋๋ฌธ์ ๋ฉ์ธ ์ค๋ ๋๋ฅผ ๋ธ๋กํนํ์ง ์๊ณ , IO ๋์คํจ์ฒ๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค.
suspend fun main() {
val time = measureTimeMillis {
coroutineScope {
repeat(50) {
launch(Dispatchers.IO) {
Thread.sleep(1000)
}
}
}
}
print(time) // ~ 1000
}
- Dispathcers.Default์ Dispathcers.IO๋ ๊ฐ์ ์ค๋ ๋ ํ์ ๊ณต์ ํฉ๋๋ค.
- ์ค๋ ๋๋ ์ฌ์ฌ์ฉ๋๊ณ ๋ค์ ๋ฐฐ๋ถ๋ ํ์๊ฐ ์์ผ๋ฉฐ, ๋ ๋ฆฝ์ ์ด๊ธฐ ๋๋ฌธ์ ๋ค๋ฅธ ๋์คํจ์ฒ์ ์ค๋ ๋๋ฅผ ๊ณ ๊ฐ์ํค๋ ๊ฒฝ์ฐ๋ ์์ต๋๋ค.
suspend fun main(): Unit = coroutineScope {
launch(Dispatchers.Default){
println(Thread.currentThread().name)
withContext(Dispatchers.IO) {
println(Thread.currentThead().name)
}
}
}
// DefaultDispatcher-worker-2
// DefaultDispatcher-worker-2
- Dispatchers.IO์์ 64๊ฐ์ ์ค๋ ๋๊น์ง ์ฌ์ฉํ ์ ์๊ณ , 8๊ฐ์ ์ฝ์ด๋ฅผ ๊ฐ์ง๊ณ ์๋ค๋ฉด ๊ณต์ ์ค๋ ๋ ํ์์ ํ์ฑํ๋ ์ค๋ ๋๋ 72๊ฐ ์ ๋๋ค.
Dispatchers.IO๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
- ๊ฐ์ฅ ํํ ๊ฒฝ์ฐ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์ ๋ธ๋กํน ํจ์๋ฅผ ํธ์ถํด์ผ ํ๋ ๊ฒฝ์ฐ์ ๋๋ค.
- ์ด๋ฐ ๊ฒฝ์ฐ withContext(Dispatchers.IO)๋ก ๋ํํ์ฌ ์ค๋จํจ์๋ฅผ ๋ง๋๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค.
withContext(Dispatchers.IO)
- ๋ฐ๋ฉด์ withContext(Dispatchers.IO)๋ก ๋ํํ ํจ์๊ฐ ๋๋ฌด ๋ง์ ์ค๋ ๋๋ฅผ ๋ธ๋กํนํ๋ฉด ๋ฌธ์ ๊ฐ ๋ ์ ์์ต๋๋ค.
- ์ด๋ฐ ๊ฒฝ์ฐ limitedParallelism์ ํ์ฉํ ์ ์์ต๋๋ค.
์ปค์คํ ์ค๋ ๋ ํ์ ์ฌ์ฉํ๋ IO ๋์คํจ์ฒ
- limitedParallelism๋ฅผ ํ์ฉํ๋ฉด ๋ ์ง์ ์ธ ์ค๋ ๋ ํ์ ๊ฐ์ง ์๋ก์ด ๋์คํจ์ฒ๋ฅผ ๋ง๋ญ๋๋ค.
- ์ด๋ ๊ฒ ๋ง๋ค์ด์ง ํ์ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋งํผ ๋ง์ ์์ ์ค๋ ๋๋ฅผ ์ค์ ํ ์ ์์ผ๋ฏ๋ก, ์ค๋ ๋ ์๋ฅผ ์ ํํ์ง ์์ต๋๋ค.(64๊ฐ ์ด์ ํ์ฉ ๊ฐ๋ฅ)
- 100๊ฐ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ Dispatchers.IO๋ ์ด 2์ด๊ฐ ๊ฑธ๋ฆฝ๋๋ค. (64๊ฐ ์ํ - 1์ด, ๋๋จธ์ง 36๊ฐ ์ํ - 1์ด)
- ๋ฐ๋ฉด์ limitedParallelism๋ฅผ ํ์ฉํ๋ฉด 100๊ฐ์ ์ค๋ ๋๋ก 1์ด๋ง์ ์ํํ ์ ์์ต๋๋ค.
launch {
val dispatcher = Dispatchers.IO
.limitedParalledlism(100)
}
- Dispatchers.Default์ limitedParallelism์ ๋์คํจ์ฒ์ ์ค๋ ๋ ์ ์ ํ์ ์ถ๊ฐํฉ๋๋ค.
- Dispatchers.IO์ limitedParallelism์ Dispatchers.Default์ ๋ ๋ฆฝ์ ์ธ ๋์คํจ์ฒ๋ฅผ ๋ง๋ค์ง๋ง, ๋ชจ๋ ์ค๋ ๋๊ฐ ๋ฌด์ ํ์ธ ์ค๋ ๋ ํ์ ํจ๊ป ๊ณต์ ํฉ๋๋ค.
- ํ๋๋ฅผ ์ง์ ํ๋ ๊ฒ์ ์ ๋ต์ ์์ง๋ง, ๋๋ฌด ๋ง์ ์ค๋ ๋๋ ์์์ ๋นํจ์จ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
- ํ์ง๋ง ์ค๋ ๋ ์๊ฐ ๋๋ฌด ์ ๋ค๋ฉด ์ฑ๋ฅ์ ์ข์ง ์์ผ๋ฏ๋ก ์ ์ ํ ๋ฐฐ์น๊ฐ ์ค์ํฉ๋๋ค.
๋ค์ํ ๋์คํจ์ฒ ํ์ฉ
์ ํด์ง ์์ ์ค๋ ๋ ํ์ ๊ฐ์ง ๋์คํจ์ฒ
- ๋ช๋ช ๊ฐ๋ฐ์๋ค์ ์์ ๋ค์ด ์ฌ์ฉํ๋ ์ค๋ ๋ ํ์ ์ง์ ๊ด๋ฆฌํ๊ธฐ ์ํ๋ฉฐ, ์๋ฐ๋ ์ด๋ฅผ ์ง์ํ๊ธฐ ์ํ ๊ฐ๋ ฅํ API๋ฅผ ์ ๊ณตํ๊ธฐ๋ ํฉ๋๋ค.
- ๋ฐ๋ฉด์ ์ด๋ฌํ ๋์คํจ์ฒ๋ close ํจ์๋ก ๋ฐ๋์ ๋ซ์์ผ ํ๋ ๋ฑ ๊ฐ๋ฐ์๊ฐ ๊น๋ฐํ ์ ์๋ ์ด์๊ฐ ์์ผ๋ฉฐ, ์ด๋ ์ค๋ ๋ ๋์๋ฅผ ์ผ์ผํค๋ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ฑ๊ธ์ค๋ ๋๋ก ์ ํ๋ ๋์คํจ์ฒ
- ๋ค์์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋ ๋ชจ๋ ๋์คํจ์ฒ๋ ๊ณต์ ์ํ๋ก ์ธํ ๋ฌธ์ ๋ฅผ ์๊ฐํด์ผํฉ๋๋ค.
var i = 0
suspend fun main(): Unit = coroutineScope {
repeat(10_000) {
launch(Dispatchers.IO) {
i++
}
}
delay(1000)
println(i) // ~9930
}
- i๋ฅผ 1์ฉ ์ฆ๊ฐ์์ผ 10000์ ๊ธฐ๋ํ๊ณ ์์ง๋ง, ์ค์ ๋ก๋ ์ด๋ณด๋ค ์์ ๊ฐ์ ๊ฐ์ง๊ฒ ๋ฉ๋๋ค.
- ๊ทธ ์ด์ ๋ ๋์ผ ์๊ฐ์ ๋ค์์ ์ค๋ ๋๊ฐ ๊ณต์ ์ํ(i ํ๋กํผํฐ)๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ๋๋ฌธ์ ๋๋ค.
- ์ฑ๊ธ์ค๋ ๋๋ฅผ ๊ฐ์ง ๋์คํจ์ฒ๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ผ๋ก ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
var i = 0
suspend fun main(): Unit = coroutineScope {
val dispatcher = Dispatchers.Default
.limitedParalledlism(1)
repeat(10_000) {
launch(dispatcher) {
i++
}
}
delay(1000)
println(i) // 10000
}
- ํ์ง๋ง ๋จ ํ๋์ ์ค๋ ๋๋ง ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์ด ์ค๋ ๋๊ฐ ๋ธ๋กํน๋๋ฉด ์์ ์ด ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌ๋๋ ๋จ์ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค.
์ ํ๋ฐ์ง ์๋ ๋์คํจ์ฒ
- Dispatchers.Unconfined๋ฅผ ํ์ฉํด ์ ํ๋ฐ์ง ์๋ ๋์คํจ์ฒ๋ฅผ ํ์ฉํ ์ ์์ต๋๋ค.
- ํธ์ถ ์ค๋ ๋์์ ์ฝ๋ฃจํด์ ์์ํ์ง๋ง ์ด๋ ์ฒซ๋ฒ์งธ ์ค๋จ์ ์ ๋ง๋ ๋ ๊น์ง๋ง ์คํ๋ฉ๋๋ค.
- ์ค๋จ์ ์ดํ ์ฝ๋ฃจํด์ด ์ฌ๊ฐ๋ ๋๋ ์ค๋จ ํจ์๋ฅผ ์ฌ๊ฐํ ์ค๋ ๋์์ ์ํ๋ฉ๋๋ค.
- ์ฝ๋ฃจํด์ด CPU ์๊ฐ์ ์๋ชจํ์ง ์๊ฑฐ๋, ๊ณต์ ๋๋ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธ ํ์ง ์๋ ๊ฒฝ์ฐ์ฒ๋ผ ํน์ ์ค๋ ๋์ ๊ตญํ๋ ์์ ์ด ์๋ ๊ฒฝ์ฐ ์ฌ์ฉํฉ๋๋ค.
- ๋ํ ๋จ์ ํ
์คํธ์ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์์ต๋๋ค.
- launch๋ฅผ ํธ์ถํ๋ ํจ์๋ฅผ ํ ์คํธํ๋ ๊ฒฝ์ฐ ์๊ฐ์ ๋๊ธฐํํ ์ ์์ต๋๋ค.
๋ฉ์ธ ๋์คํจ์ฒ๋ก ์ฆ์ ์ฎ๊ธฐ๊ธฐ
- ์ฝ๋ฃจํด์ ๋ฐฐ์ ํ๋ ๊ฒ์๋ ๋น์ฉ์ด ๋ค๋ฉฐ, withContext๊ฐ ํธ์ถ๋๋ฉด ์ฝ๋ฃจํด์ ์ค๋จ๋๊ณ ํ์์ ๊ธฐ๋ค๋ฆฌ๋ค๊ฐ ์ฌ๊ฐ๋ฉ๋๋ค.
- ์ค๋ ๋์์ ์ด๋ฏธ ์คํ๋๊ณ ์๋ ์ฝ๋ฃจํด์ ๋ค์ ๋ฐฐ์ ํ๋ฉด ์์ง๋ง ํ์ ์๋ ๋น์ฉ์ด ๋ค ์ ์์ต๋๋ค.
suspend fun showUser(user: User) =
withContext(Dispatchers.Main.immediate) {
userNameElement.text = user.name
}
- Dispatchers.Main.immediate๋ฅผ ํ์ฉํด ํ์ํ ๊ฒฝ์ฐ์๋ง ๋ฐฐ์ ํ ์ ์์ต๋๋ค.
์์ฝ
- ๋์คํจ์ฒ๋ ์ฝ๋ฃจํด์ด ์คํ๋ ์ค๋ ๋๋ ์ค๋ ๋ ํ์ ๊ฒฐ์ ํฉ๋๋ค.
- Dispatchers.Default๋ CPU ์ง์ฝ์ ์ธ ์ฐ์ฐ์ ์ฌ์ฉํฉ๋๋ค.
- Dispatchers.Main์ Android, Swing, JavaFX์์ ๋ฉ์ธ ์ค๋ ๋์ ์ ๊ทผํ ๋ ์ฌ์ฉํฉ๋๋ค.
- Dispatchers.Main.immediate๋ Dispatchers.Main์ด ์ฌ์ฉํ๋ ์ค๋ ๋์์ ์คํ๋์ง๋ง ๊ผญ ํ์ํ ๋๋ง ์ฌ๋ฐฐ์ ๋ฉ๋๋ค.
- Dispatchers.IO๋ ๋ธ๋กํน ์ฐ์ฐ์ ํ ํ์๊ฐ ์์ ๋ ์ฌ์ฉํฉ๋๋ค.
- Dispatchers.Unconfined๋ ์ฝ๋ฃจํด์ด ์คํ๋ ์ค๋ ๋์ ๋ํด์ ์ ๊ฒฝ ์ธ ํ์๊ฐ ์์ ๋ ์ฌ์ฉํฉ๋๋ค.
์ฐธ๊ณ
https://medium.com/@sahilthakar10/dispatchers-io-and-default-under-the-hood-b39aee24d2e9