Android
[Coroutine] 1-5 코루틴 컨텍스트와 디스패처 (1, 2)
Diane_KIM
2024. 6. 9. 23:21
f 디스패처 종류들
코루틴이 실행될 스레드를 결정해주는 객체
fun main() = runBlocking {
launch {
println("부모의 컨텍스트 : ${Thread.currentThread().name}")
// 부모의 컨텍스트 : main
}
launch(Dispatchers.Default) {
println("Default: ${Thread.currentThread().name}")
// IO: DefaultDispatcher-worker-2
}
launch(Dispatchers.IO) {
println("IO: ${Thread.currentThread().name}")
// IO: DefaultDispatcher-worker-2
}
launch(Dispatchers.Unconfined) {
println("Unconfined: ${Thread.currentThread().name}")
// Unconfined: main
}
launch(newSingleThreadContext("Fast campus")) {
println("newSingleThreadContext : ${Thread.currentThread().name}")
// newSingleThreadContext : Fast campus
}
}
- Default : 코어 수에 비례하는스레드 풀에서 수행 (주로 사용 ⭐️)
- IO : 코어 수 보다 훨씬 많은 스레드를 가지고 있는 스레드 풀. IO 작업은 CPU를 덜 소요하기 떄문 (주로 사용 ⭐️)
- Unconfined : 어디에도 속하지 않음. 앞으로 어디에서 수행될지 알 수 없음
- newSingleThreadContext : "항상" 새로운 스레드를 만듦. 스레드 이름을 지정할 수 있음
* 예제에서는 launch를 사용했지만 async, withContext, runBlocking (대부분의 코루틴빌더)에서도 사용 가능
* Unconfined 는 처음에는 부모의 스레드에서 수행되지만, 중단점(delay)이 오면 바뀌게 된다. 어느 디스패처에서 수행할지 예측이 어렵기 때문에, 가능하면 확실한 디스패처를 사용할 것을 추천
부모가 있는 Job과 없는 Job
코루틴 스코프, 코르틴 컨텍스트는 구조화되어있고 부모에게 계층적으로 되어 있다. 이 관계에서 부모 코루틴이 취소되면 자식도 함께 취소된다. 하지만 Job()을 사용하여 새로운 코루틴을 생성하면, 그 코루틴은 독립적인 Job을 가지게 되어 부모의 Job과는 별도로 관리되며, 부모 코루틴이 취소되거나 종료하더라도 영향을 받지 않는다.
fun main() = runBlocking<Unit> {
val job = launch {
launch(Job()) {
println(coroutineContext[Job])
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("3!")
}
launch {
println(coroutineContext[Job])
println("launch2: ${Thread.currentThread().name}")
delay(1000L)
println("1!")
}
}
delay(500L)
job.cancelAndJoin()
delay(1000L)
}
결과는
- StandaloneCoroutine{Active}@c39f790
- launch1: main
- StandaloneCoroutine{Active}@71e7a66b
- launch2: main
- 3!
Job()을 새로만든 코루틴의 빌더는 부모의 영향을 받지 않아 취소되지 않으므로 3!이 출력된다
코루틴 엘리먼트 결합
코루틴 엘리먼트를 한번에 사용할 수 있다 + 연산으로 엘리먼트를 합치면 된다. 합쳐진 엘리먼트들은 coroutineContext[XXX]로 조회할 수 있다.
fun test() = runBlocking<Unit> {
launch {
launch(Dispatchers.IO + CoroutineName("launch1")) {
println("launch1: ${Thread.currentThread().name}")
println(coroutineContext[CoroutineDispatcher])
println(coroutineContext[CoroutineName])
delay(5000L)
}
launch(Dispatchers.Default + CoroutineName("launch2")) {
println("launch2: ${Thread.currentThread().name}")
println(coroutineContext[CoroutineDispatcher])
println(coroutineContext[CoroutineName])
delay(10L)
}
}
}
launch(Dispatcher.IO + CoroutineName)는 CoroutineContext라고 함. 부모와 자식의 코루틴 컨텍스트를 합치는 형태로 되어 있다.
launch(부모) > A(부모 컨텍스트), launch(Dispatcher.IO) > B, launch(CoroutineName()) > C 라고 하면
코루틴 컨텍스트는 A+B+C 총 세개의 엘리먼트로 만들어진 컨텍스트이다