#1 ์ด์ ๊ธ
[Kotlin] Coroutines - Coroutine builder
#1 Coroutine builder kotlinx-coroutines-coreCore primitives to work with coroutines. Coroutine builder functions: Coroutine dispatchers implementing CoroutineDispatcher: More context elements: Synchronization primitives for coroutines: Top-level suspendin
kenel.tistory.com
์ ๊ฒ์๊ธ์ CoroutineScope์ ์๋ต์ ๋ํด ๋ค๋ฃฌ #6-4์์ ์ด์ด์ง๋ ๊ธ์ด๋ค. ์ด์ ๊ธ์์ CoroutineScope์ ์๋ตํ๋ ๊ฒ, ๊ฐ๋
์ฑ ์ด์ธ์ ์๋ฏธ๊ฐ ์๋ค๊ณ ํ๋ค. ๊ทธ๊ฒ์ ๋ฐ๋ก ํ๋์ CoroutineScope ๋ด Coroutine ๊ฐ ๋ถ๋ชจ-์์ ๊ณ์ธต์ ๊ตฌํ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ์ด ํ๋์ CoroutineScope ๋ด Coroutine ๊ฐ ๋ถ๋ชจ-์์ ๊ณ์ธต์ ๊ตฌํ์ join() ๋ฐ cancel()์์์ ์ด์ ์ ๊ฐ์ง๋ค (join()์์์ ์ด์ ์ join()๊ณผ ๊ฐ์ ๋งฅ๋ฝ์ ํจ์์ธ await()๋ receive()์๋ ์ ์ฉ๋๋ค).
์ด ์ด์ ๋ค์ ์ค๋ช
ํ๊ธฐ ์์, Coroutine ๊ฐ ๋ถ๋ชจ-์์ ๊ณ์ธต์ด ์ด๋ค ๋ชจ์์ผ๋ก ํํ๋๋์ง๋ฅผ ๋จผ์ ์ง๊ณ ๋์ด๊ฐ ํ์๊ฐ ์๋ค.
#2 ๋จ์ผ Scope ๋ด ๋ณต์์ Coroutines ๊ฐ ๋ถ๋ชจ-์์ ๊ณ์ธต ํ์ฑ์ ์์
#2-1 CoroutineScope๋ฅผ ์๋ตํ์ง ์์ ์ฝ๋
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
suspend fun main() {
val coroutine1 = CoroutineScope(Dispatchers.Default).launch {
val coroutine2 = CoroutineScope(Dispatchers.Default).launch {
delay(1000)
println("coroutine2 is done.")
}
val coroutine3 = CoroutineScope(Dispatchers.Default).launch {
delay(8000)
println("coroutine3 is done.")
}
val coroutine4 = CoroutineScope(Dispatchers.Default).launch {
delay(6000)
println("coroutine4 is done.")
}
delay(4000)
println("coroutine1 is done.")
}
coroutine1.join()
println("End")
}
suspend ํค์๋์ ๋ํด ๋ชจ๋ฅธ๋ค๋ฉด ์ด ๊ฒ์๊ธ์ ์ฐธ์กฐํ๋ค. ์ ์ฝ๋๋ CoroutineScope ์์ ๋ ๋ค๋ฅธ CoroutineScope๊ฐ ์์นํ ์ฝ๋๋ค. ์ด ์ฝ๋๋ฅผ ๋์๋๋ก ํํํ๋ฉด ์๋์ ๊ฐ๋ค.

์ด 4๊ฐ์ ์ฝ๋ฃจํด์ด ์ํ๋๋ฉฐ, ๊ทธ ์ฝ๋ฃจํด์ ๊ฐ๊ฐ ๋ค๋ฅธ ์ฝ๋ฃจํด ์ค์ฝํ์ ๋ค์ด์๊ฒ ๋๋ค. ์ด ๋์๋์์ coroutine2 ~ 4๊ฐ coroutine1์ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ด๋ฃฌ๋ค๊ณ ์คํดํด์๋ ์ ๋๋ค. coroutine2 ~ 4์ coroutine1์ ์ฝ๋ ๋ด์ฉ์ ์ํด ์์ฑ๋์์ ๋ฟ ์๋ฌด๋ฐ ๊ด๋ จ์ด ์๋ค (๋ฌผ๋ก ํธ์ถํจ-ํธ์ถ๋จ์ด๋ผ๋ ๊ด์ ์์๋ ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ด๋ฃฌ๋ค๊ณ ๋ณผ ์ ์์ง๋ง, ์ผ๋ฐ์ ์ผ๋ก ๊ณ์ธต ๊ด๊ณ๋ฅผ ์๋ฏธํ๋ ๋ถ๋ชจ-์์ ๊ด๊ณ๋ ์๋๋ผ๋ ๋ง์ด๋ค).
#2-2 CoroutineScope๋ฅผ ์๋ตํ ์ฝ๋
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
suspend fun main() {
val coroutine1 = CoroutineScope(Dispatchers.Default).launch {
val coroutine2 = launch {
delay(1000)
println("coroutine2 is done.")
}
val coroutine3 = launch {
delay(8000)
println("coroutine3 is done.")
}
val coroutine4 = launch {
delay(6000)
println("coroutine4 is done.")
}
delay(4000)
println("coroutine1 is done.")
}
coroutine1.join()
println("End")
}
์ด์ ๊ธ(#1)์ ๋ด์ฉ์ ๊ธฐ๋ฐํด Coroutine Builder์ ์๋ต์ ๊ตฌํํ ์ฝ๋๋ค. ์ฒซ CoroutineScope ์ธ์๋ ์ถ๊ฐ์ ์ธ CoroutineScope๊ฐ ์ฐ์ด์ง ์์๋ค. ์ด ์ฝ๋๋ฅผ ๋์๋๋ก ํํํ๋ฉด ์๋์ ๊ฐ๋ค.

#2-1์ ๋์๋์ ๋ถ๋ช
ํ ์ฐจ์ด๊ฐ ๋ณด์ธ๋ค. 4๊ฐ์ ์ฝ๋ฃจํด์ด ์ํ๋๋ ๊ฒ์ ๋์ผํ์ง๋ง ๋ชจ๋ ํ๋์ CoroutineScope๋ฅผ ๊ณต์ ํ๊ณ ์๋ค. ์ฆ, CoroutineScope๋ฅผ ์๋ตํ๋ ๊ฒ์ ์๋ฏธ๋ ๋จ์ํ ๊ฐ๋
์ฑ ํฅ์์ ๊ทธ์น์ง ์์ผ๋ฉฐ, ์ด๋ ๊ฒ ๋ค๋ฅธ ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด๋ด๋ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ ๊ฒ ์ด๋ค ์ฝ๋ฃจํด ์ค์ฝํ ๋ด์์ ๋ ๋ค๋ฅธ ์ฝ๋ฃจํด์ CoroutineScope์ ์๋ตํด ํธ์ถํ๋ฉด, ํธ์ถ๋ coroutine์ ํธ์ถํ coroutine์ ์์ coroutine์ด ๋๋ค.
๊ทธ๋ ๋ค๋ฉด, ์ฝ๋ฃจํด์์ ๋ถ๋ชจ-์์์ ๊ณ์ธตํ๋ฅผ ํ์ฑํ๋ ๊ฒ์ ์ด๋ค ์ด์ ์ด ์๋๊ฐ?
#3 ์ฝ๋ฃจํด ๊ณ์ธตํ์ ์ด์
#3-1 ์ผ๊ด์ join()
CoroutineScope๋ฅผ ์๋ตํ์ง ์์ #2-1์ ์ถ๋ ฅ ๊ฒฐ๊ณผ
coroutine2 is done.
coroutine1 is done.
End
CoroutineScope๋ฅผ ์๋ตํ #2-2์ ์ถ๋ ฅ ๊ฒฐ๊ณผ
coroutine2 is done.
coroutine1 is done.
coroutine4 is done.
coroutine3 is done.
End
CoroutineScope๋ฅผ ์๋ตํ์ง ์์ #2-1์ ์ถ๋ ฅ ๊ฒฐ๊ณผ์, CoroutineScope๋ฅผ ์๋ตํ #2-2์ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ค. ๋ ์ฝ๋ ๋ชจ๋ corotuine1.join()์ ์ํํ์์๋, ํ์์ ์ฝ๋์ ๋ฌ๋ฆฌ ์ ์๋ ์๋ฃ๋์ง ์์ ์ฝ๋ฃจํด์ด ์กด์ฌํจ์ ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ฅผ ํตํด ์ ์ ์๋ค (ํ๋ก๊ทธ๋จ์ด ์ข
๋ฃ๋ ๋๊น์ง ์๋ฃ๋์ง ์์ ์ฝ๋ฃจํด์ ์ถ๋ ฅ์ด ๋ถ๊ฐ๋ฅํ๋ค). ์ด๋ ๋ถ๋ชจ ์ฝ๋ฃจํด์ join()์ ์ํํ๋ฉด, ์์ ์ฝ๋ฃจํด๋ ์์์ ์ผ๋ก join()์ด ์ํ๋๊ธฐ ๋๋ฌธ์ด๋ค. ์ฆ ์ฝ๋ฃจํด์ ๊ณ์ธตํ๋ฅผ ์์
ํด๋๋ฉด, ์ผ์ผํ ๋ชจ๋ ํ์(์์) ์ฝ๋ฃจํด์ join()์ ์ํํ ํ์๊ฐ ์์ด์ง๋ค (์ด join()์์์ ์ด์ ์ join()๊ณผ ๊ฐ์ ๋งฅ๋ฝ์ ํจ์์ธ await()๋ receive()์๋ ์ ์ฉ๋๋ค).
#3-2 ์ผ๊ด์ cancle()
import kotlinx.coroutines.*
suspend fun main() {
val coroutine1 = CoroutineScope(Dispatchers.Default).launch {
// coroutine1์ ์์
val coroutine2 = launch {
while (isActive) {
println("coroutine2 is running... on ${Thread.currentThread().name}")
delay(1000)
}
}
// coroutine1์ ์์
val coroutine3 = launch {
while (isActive) {
println("coroutine3 is running... on ${Thread.currentThread().name}")
delay(1000)
}
}
// ๋
๋ฆฝ์ ์ธ ์ฝ๋ฃจํด (coroutine1์ ์์ ์๋)
val coroutine4 = CoroutineScope(Dispatchers.Default).launch {
while (isActive) {
println("coroutine4 is running... on ${Thread.currentThread().name}")
delay(1000)
}
}
while (isActive) {
println("coroutine1 is running... on ${Thread.currentThread().name}")
delay(1000)
}
}
delay(5000)
coroutine1.cancel()
delay(10000)
println("End")
}
/* ์ถ๋ ฅ ๊ฒฐ๊ณผ
coroutine2 is running... on DefaultDispatcher-worker-3
coroutine1 is running... on DefaultDispatcher-worker-1
coroutine3 is running... on DefaultDispatcher-worker-4
coroutine4 is running... on DefaultDispatcher-worker-1
coroutine2 is running... on DefaultDispatcher-worker-2
coroutine1 is running... on DefaultDispatcher-worker-3
coroutine3 is running... on DefaultDispatcher-worker-1
coroutine4 is running... on DefaultDispatcher-worker-4
coroutine2 is running... on DefaultDispatcher-worker-4
coroutine3 is running... on DefaultDispatcher-worker-3
coroutine1 is running... on DefaultDispatcher-worker-1
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine2 is running... on DefaultDispatcher-worker-2
coroutine1 is running... on DefaultDispatcher-worker-3
coroutine4 is running... on DefaultDispatcher-worker-4
coroutine3 is running... on DefaultDispatcher-worker-1
coroutine2 is running... on DefaultDispatcher-worker-1
coroutine4 is running... on DefaultDispatcher-worker-3
coroutine3 is running... on DefaultDispatcher-worker-2
coroutine1 is running... on DefaultDispatcher-worker-4
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
coroutine4 is running... on DefaultDispatcher-worker-2
End
*/
์ผ๊ด์ join()๊ณผ ๊ฐ์ ๋งฅ๋ฝ์ผ๋ก, ๋ถ๋ชจ ์ฝ๋ฃจํด์ cancle()ํ๋ฉด ์์ ์ฝ๋ฃจํด๋ค ๋ํ ์ผ๊ด์ ์ผ๋ก cancle()๋๋ค.
coroutine2 ~ 3์ coroutine1์ ์์์ผ๋ก ๋์ง๋ง, coroutine4๋ ๋ณ๋์ ๋
๋ฆฝ์ ์ธ ์ฝ๋ฃจํด์ผ๋ก ๋๋ค. ์ถ๋ ฅ ๊ฒฐ๊ณผ๋ ๋ณด๋ฉด coroutine1์ด ์ทจ์๋๊ธฐ ์ ๊น์ง ์ฆ 5์ด ๋์ coroutine1 ~ 4 ๋ชจ๋๊ฐ ์คํ๋๋ค. ํ์ง๋ง ๊ทธ ํ coroutine1.cancel()์ด ์คํ๋๊ณ , coroutine1๊ณผ ๊ทธ ์์์ธ coroutine2 ~ 3์ด ์์์ ์ผ๋ก ์ทจ์๋๋ค. ์ดํ coroutine4๋ง ์คํ๋๋ ๋ชจ์ต์ ํ์ธํ ์ ์๋ค. coroutine4๋ฅผ ํธ์ถํ ๊ฒ์ ๋ถ๋ช
coroutine1์์ผ๋, ๊ทธ๋ ๋ค๊ณ coroutine4๊ฐ coroutine1์ ์์์ด ๋๋ ๊ฑด ์๋๊ธฐ ๋๋ฌธ์ด๋ค.
์ฌ๋ด์ผ๋ก, ์ค๋ ๋ํ์ ์ค๋ ๋๋ต๊ฒ ์ฝ๋ฃจํด ํ๋๊ฐ ์ค๋ ๋ ํ๋๋ฅผ ๊ณ์ ์ ์ ํ๋ ๊ฒ ์๋, ๋ฐ๋ฉ๊ณผ ์ฌ์ฌ์ฉ์ ๋ฐ๋ณตํ๋ ๊นจ์๊ฐ์ ๋ชจ์ต๋ ์ถ๋ ฅ ๊ฒฐ๊ณผ์์ ํ์ธํ ์ ์๋ค.
#4 ๋น์ทํ ๊ธ
[Kotlin] Coroutines - Structured Concurrency
#1 Unstructured Concurrency์ฝ๋ฃจํด ์ฝ๋๋ฅผ ์ค๊ณํ ๋ ์กฐ์ฌํด์ผ ํ๋ ์ ์ด ์๋ค. ๋ค์ ์ฝ๋๋ฅผ ๋ณด์. #1-1 ์ฝ๋import kotlinx.coroutines.*class MyClass { suspend fun getMyCount(): Int { var count = 0 CoroutineScope(Dispatchers.IO).lau
kenel.tistory.com
์ ๊ฒ์๊ธ์ ๋ณธ ๊ฒ์๊ธ๊ณผ ๋น์ทํ ๋ด์ฉ์ ๋ค๋ฃฌ๋ค. ๋ฐ๋ก, ์์์ join()์ ์ํ์ ๋ํ ๋ด์ฉ์ด๋ค. ์ฐจ์ด์ ์ด๋ผ๋ฉด, ๋ณธ ๊ฒ์๊ธ์์ ์์ ์ฝ๋ฃจํด์ ์์์ join()์ ๋ํด ๋ค๋ค๋ค๋ฉด, ์ ๊ฒ์๊ธ์์ ๋ถ๋ชจ ์ฝ๋ฃจํด์ ์์์ join()์ ๋ํด ๋ค๋ฃฌ๋ค.
'๊นจ์ ๊ฐ๋ ๐ > Kotlin' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Kotlin] Coroutines Flow - Back pressure์ ๊ทธ ์ฒ๋ฆฌ (0) | 2024.08.15 |
---|---|
[Kotlin] Coroutines Flow - ๊ธฐ์ด (0) | 2024.08.01 |
[Kotlin] ์์ ํ๋กํผํฐ (Delegated properties) (0) | 2024.07.22 |
[Kotlin] Coroutines - ViewModelScope (0) | 2024.02.20 |
[Kotlin] Coroutines - ์ค๋ ๋ ์ ํ (0) | 2024.02.19 |