스위치 스레드
JVM 옵션에 -Dkotlinx.coroutines.debug를 넣어 다음 코드를 실행해 보겠습니다(디버그 확인).
newSingleThreadContext("Ctx1").use { ctx1 ->
newSingleThreadContext("Ctx2").use { ctx2 ->
runBlocking(ctx1) {
log("Started in ctx1")
withContext(ctx2) {
log("Working in ctx2")
}
log("Back to ctx1")
}
}
}
완전한 코드는 여기에서 찾을 수 있습니다
그것은 몇 가지 새로운 기술을 보여줍니다. 하나는 실행 차단명시적으로 인스턴스화된 컨텍스트가 있고 다른 하나는 다음 출력에서 볼 수 있는 것과 같습니다. 맥락과 함께 동일한 코루틴을 유지하면서 함수를 사용하여 컨텍스트를 변경할 수 있습니다.
(Ctx1 @coroutine#1) Started in ctx1
(Ctx2 @coroutine#1) Working in ctx2
(Ctx1 @coroutine#1) Back to ctx1
또한 이 예에서 Kotlin 표준 라이브러리는 사용 기능 newSingleThreadContext더 이상 필요하지 않을 때 생성된 스레드를 해제하는 데 사용됩니다.
이 문서는 공식 코루틴 문서를 번역한 것입니다.
원래의: 코루틴 컨텍스트 및 디스패처 – 스레드 간 점프
원본 텍스트의 최종 편집: 2022년 6월 27일
상황에 맞는 직업
코루틴의 작업은 Context, coroutineContext(Job)*1의 구성 요소입니다. 식에서 얻을 수 있습니다.
fun main() = runBlocking<Unit> {
println("My job is ${coroutineContext(Job)}")
}
완전한 코드는 여기에서 찾을 수 있습니다
디버그 모드의 출력은 다음과 같습니다.
My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
CoroutineScope~에서 활성~이다 coroutineContext(Order)?.isActive == true 편리한 사용을 위한 바로가기*2입니다.
다음 내용은 독자의 이해를 돕기 위해 번역자가 추가한 내용입니다.
*하나. CoroutineContext는 맵 형식의 내부 요소를 관리합니다. Map의 키 값에 Job이 입력되면 CoroutineContext에서 Job 컴포넌트가 추출됩니다.
public interface Job : CoroutineContext.Element {
...
public companion object Key : CoroutineContext.Key<Job>
...
}
*2. CoroutineScope.isActive 확장 함수는 CoroutineScope의 coroutineContext에서 작업 개체를 가져온 다음 작업이 활성 상태인지 확인하고 null이면 true를 반환합니다.
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
public val CoroutineScope.isActive: Boolean
get() = coroutineContext(Job)?.isActive ?: true
즉, coroutineScope에는 CoroutineContext가 하나만 존재하며, CoroutineContext 내에서는 CoroutineContext.Key를 상속받은 Key 값과 Key 값에 해당하는 Value 값으로 컴포넌트를 관리한다. 이 구성요소에는 코루틴이 현재 실행 중인지 확인하는 작업이 포함되어 있습니다.
이 문서는 공식 코루틴 문서를 번역한 것입니다.
원래의: 코루틴 컨텍스트 및 디스패처 – 컨텍스트의 작업
원본 텍스트의 최종 편집: 2022년 6월 27일
코 루틴의 자식
코루틴은 다른 코루틴 내에 중첩될 수 있습니다. CoroutineScope내부에서 실행되는 경우 CoroutineScope.coroutineContext다음을 통해 상속된 새로운 코루틴 일하다부모 코 루틴입니다 일하다Child are kill by 부모 코루틴이 취소되면 자식 코루틴도 재귀적으로 취소됩니다.
그러나 부모-자식 관계는 두 가지 방법으로 명시적으로 재정의할 수 있습니다.
- 코루틴을 실행할 때 두 개의 서로 다른 범위가 명시적으로 설정된 경우(예: GlobalScope 시작), 상위 영역에서 일하다상속하지 마십시오.*1
- 새 코루틴의 컨텍스트에 다른 작업이 전달되면(아래 예 참조) 상위 범위 작업을 덮어씁니다.*2
두 경우 모두 실행 중인 코루틴은 실행 중인 범위에 바인딩되지 않고 독립적으로 작동합니다.
// launch a coroutine to process some kind of incoming request
val request = launch {
// it spawns two other jobs
launch(Job()) {
println("job1: I run in my own Job and execute independently!")
delay(1000)
println("job1: I am not affected by cancellation of the request")
}
// and the other inherits the parent context
launch {
delay(100)
println("job2: I am a child of the request coroutine")
delay(1000)
println("job2: I will not execute this line if my parent request is cancelled")
}
}
delay(500)
request.cancel() // cancel processing of the request
println("main: Who has survived request cancellation?")
delay(1000) // delay the main thread for a second to see what happens
완전한 코드는 여기에서 찾을 수 있습니다
코드를 실행한 결과는 다음과 같습니다.
job1: I run in my own Job and execute independently!
job2: I am a child of the request coroutine
main: Who has survived request cancellation?
job1: I am not affected by cancellation of the request
다음 내용은 독자의 이해를 돕기 위해 번역자가 추가한 내용입니다.
*하나. 아래와 같이 CoroutineScope(Dispatchers.IO)로 CoroutineScope를 재정의한다고 가정합니다.
fun main() = runBlocking<Unit> {
CoroutineScope(Dispatchers.IO).launch {
...
}
}
CoroutineContext가 CoroutineScope에 의해 재정의되면 CoroutineContext는 부모에서 상속되지 않으므로 작업이 없습니다. 따라서 아래와 같이 컨텍스트의 작업이 null인 경우 컨텍스트에 작업을 추가하여 CoroutineScope를 생성합니다.
@Suppress("FunctionName")
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
ContextScope(if (context(Job) != null) context else context + Job())
따라서 그녀는 부모 코루틴과 다른 직업을 가집니다.
*2. CoroutineContext는 구성 요소를 키-값으로 관리합니다. 즉, 핵심 작업에 해당하는 값은 하나뿐입니다. 따라서 CoroutineContext에 새로운 job이 지정되면 key job에 해당하는 Value가 새로운 job이 된다.
이 문서는 공식 코루틴 문서를 번역한 것입니다.
원래의: 코루틴 컨텍스트 및 디스패처 – 코루틴의 자식
원본 텍스트의 최종 편집: 2022년 6월 27일
