반응형
코루틴 컨텍스트 (CoroutineContext)
- Job 계층의 생명 주기를 연결하기 위해 사용
코루틴 컨텍스트 구현체
// kotlin.coroutines.CoroutineContext.class
@kotlin.SinceKotlin public interface CoroutineContext {
public abstract operator fun <E : kotlin.coroutines.CoroutineContext.Element> get(key: kotlin.coroutines.CoroutineContext.Key<E>): E?
public abstract fun <R> fold(initial: R, operation: (R, kotlin.coroutines.CoroutineContext.Element) -> R): R
public open operator fun plus(context: kotlin.coroutines.CoroutineContext): kotlin.coroutines.CoroutineContext { /* compiled code */ }
public abstract fun minusKey(key: kotlin.coroutines.CoroutineContext.Key<*>): kotlin.coroutines.CoroutineContext
public interface Key<E : kotlin.coroutines.CoroutineContext.Element> {
}
public interface Element : kotlin.coroutines.CoroutineContext {
public abstract val key: kotlin.coroutines.CoroutineContext.Key<*>
public open operator fun <E : kotlin.coroutines.CoroutineContext.Element> get(key: kotlin.coroutines.CoroutineContext.Key<E>): E? { /* compiled code */ }
public open fun <R> fold(initial: R, operation: (R, kotlin.coroutines.CoroutineContext.Element) -> R): R { /* compiled code */ }
public open fun minusKey(key: kotlin.coroutines.CoroutineContext.Key<*>): kotlin.coroutines.CoroutineContext { /* compiled code */ }
}
}
- Composite Design Pattern(복합체 패턴)을 이용하여 중첩된 스코프의 실행 위치를 추적할 수 있도록 설계
- CoroutineScope는 CoroutineContext의 컨테이너 역할을 하여 Job을 그룹화 시킴
- CoroutineContext는 코루틴 동작을 설명하는 요소들의 집합
코루틴 컨텍스트 특징
- 병합하거나 분해할 수 있음
- EmptyCoroutineContext → 요소가 없는 상태
- Element → 요소가 하나인 상태
- CombinedContext → 요소가 2개 이상인 상태
- Key → 요소를 구분할 때 사용하는 식별자
fun main() {
val handler = CoroutineExceptionHandler { _, e ->
println("CoroutineExceptionHandler")
}
val context1 = CoroutineName("Custom Coroutine") +
Dispatchers.Default +
Job() +
handler
println("context: $context1")
val context2 = context1.minusKey(CoroutineExceptionHandler)
println("context2: $context2")
val context3 = context2.minusKey(Job)
println("context3: $context3")
val context4 = context3.minusKey(CoroutineDispatcher)
println("context4: $context4")
val context5 = context4.minusKey(CoroutineName)
println("context5: $context5")
}
/*
실행 결과:
context: [CoroutineName(Custom Coroutine), JobImpl{Active}@5197848c, TestKt$main$$inlined$CoroutineExceptionHandler$1@17f052a3, Dispatchers.Default]
context2: [CoroutineName(Custom Coroutine), JobImpl{Active}@5197848c, Dispatchers.Default]
context3: [CoroutineName(Custom Coroutine), Dispatchers.Default]
context4: CoroutineName(Custom Coroutine)
context5: EmptyCoroutineContext
*/
Job
- CoroutineContext의 요소
Job 구현체
// kotlinx.coroutines.Job.kt
@Suppress("FunctionName")
public fun Job(parent: Job? = null): CompletableJob = JobImpl(parent)
// kotlinx.coroutines.CompletableJob.kt
@OptIn(ExperimentalSubclassOptIn::class)
@SubclassOptInRequired(markerClass = InternalForInheritanceCoroutinesApi::class)
public interface CompletableJob : Job {
public fun complete(): Boolean
public fun completeExceptionally(exception: Throwable): Boolean
}
// kotlinx.coroutines.Job.kt
@OptIn(ExperimentalSubclassOptIn::class)
@SubclassOptInRequired(markerClass = InternalForInheritanceCoroutinesApi::class)
public interface Job : CoroutineContext.Element {
public companion object Key : CoroutineContext.Key<Job>
public val parent: Job?
public val isActive: Boolean
public val isCompleted: Boolean
public val isCancelled: Boolean
public fun getCancellationException(): CancellationException
public fun start(): Boolean
public fun cancel(cause: CancellationException? = null)
public val children: Sequence<Job>
public fun attachChild(child: ChildJob): ChildHandle
public suspend fun join()
public val onJoin: SelectClause0
public fun invokeOnCompletion(handler: CompletionHandler): DisposableHandle
public fun invokeOnCompletion(
onCancelling: Boolean = false,
invokeImmediately: Boolean = true,
handler: CompletionHandler): DisposableHandle
}
- 상태를 가짐
- Active
- Completed
- Cancelled
- start, cancel을 통해 명시적으로 작업 가능
- children을 통해 다른 Job의 생명주기 관리 가능
코루틴 디스패쳐(Coroutine Dispatcher)
- 스레드간 코루틴을 분산하는 orchestrator
- 코루틴을 실행하고자 하는 스레드를 지정하는 역할
Coroutine Dispatcher 구현체
// kotlinx.coroutines.Dispatchers.kt
public actual object Dispatchers {
@JvmStatic
public actual val Default: CoroutineDispatcher = DefaultScheduler
@JvmStatic
public actual val Main: MainCoroutineDispatcher get() = MainDispatcherLoader.dispatcher
@JvmStatic
public actual val Unconfined: CoroutineDispatcher = kotlinx.coroutines.Unconfined
@JvmStatic
public val IO: CoroutineDispatcher get() = DefaultIoScheduler
@DelicateCoroutinesApi
public fun shutdown() {
DefaultExecutor.shutdown()
// Also shuts down Dispatchers.IO
DefaultScheduler.shutdown()
}
}
- Default
- CPU 개수만큼 스레드 생성
- CPU를 많이 사용하는 무거운 작업에 최적화
- Main
- 화면 UI 작업을 위해 사용
- Android 개발 모듈에서 주로 사용
- IO
- 최대 64개까지 늘어나는 가변 크기의 스레드 풀 사용
- kotlinx.coroutines.io.parallelism 로 조절 가능
- 네트워크, DB I/O 등 사용
- 읽기, 쓰기 작업에 최적화
- Thread를 Block할 필요가 있는 경우
- 최대 64개까지 늘어나는 가변 크기의 스레드 풀 사용
반응형