서론
대표적인 코루틴 빌더 함수인 launch와 async의 코드를 보면 다음과 같습니다.
위 코드 스니펫에서 볼 수 있다시피 launch와 async 함수는 매개변수로 context, start, block을 가집니다.
- context의 타입은 CoroutineContext
- start의 타입은 CoroutineStart
- launch 함수의 block은 Unit을 반환하는 람다식
- async 함수의 block은 제네릭 타입 T를 반환하는 람다식
CoroutineContext는 코루틴을 실행하는 실행 환경을 설정하고 관리하는 인터페이스로 CoroutineContext 객체는 다음의 객체들을 조합해 코루틴의 실행 환경을 설정합니다.
- CoroutineDispatcher
- CoroutineName
- Job
- etc.
정리하자면 CoroutineContext 객체는 코루틴을 실행하고 관리하는 데 핵심적인 역할을 수행하며 코루틴의 실행과 관련된 모든 설정은 CoroutineContext 객체를 통해 이뤄집니다.
CoroutineContext 구성 요소
- CoroutineContext 객체는 CoroutineName, CoroutineDispatcher, Job, 그리고 CoroutineExceptionHandler의 네 가지 구성 요소를 가지며 각각의 요소는 다음과 같은 역할을 수행
- CoroutineName: 코루틴 이름 설정
- CoroutineDispatcher: 코루틴을 쓰레드에 할당하고 실행
- Job: 코루틴의 추상체로 코루틴을 조작하는 데 사용
- CoroutineExceptionHandler: 코루틴에서 발생한 예외를 처리
CoroutineContext 구성하기
1. CoroutineContext 구성 요소를 관리하는 방법
- CoroutineContext 객체는 key-value 쌍으로 앞서 말한 네 가지 구성 요소를 관리하며 각 객체를 한 개씩만 가질 수 있음
- CoroutineName key - CoroutineName 객체
- CoroutineDispatcher key - CoroutineDispatcher 객체
- Job key - Job 객체
- CoroutineExceptinHandler key - CoroutineExceptionHandler 객체
* 각 구성 요소는 고유한 키를 가지며, 키에 대해 중복된 값 허용 X
2. CoroutineContext 구성
- 앞서 언급했다시피 CoroutineContext 객체는 key-value 쌍으로 구성 요소를 관리
- 하지만 키에 값을 직접 대입하는 방법 X
- CoroutineContext 객체 간에 더하기 연산을 사용해 CoroutineContext 객체 구성
부연 설명
- MyThread 쓰레드를 사용해 실행되고 더하기 연산을 통해 코루틴명은 MyCoroutine으로 설정된 것을 확인 가능
3. CoroutineContext 구성 요소 덮어씌우기
- CoroutineContext 객체에 같은 구성 요소가 둘 이상 더해질 경우 나중에 추가된 CoroutineContext 구성 요소가 이전의 값을 덮어 씌움
4. 여러 구성 요소로 이뤄진 CoroutineContext 합치기
- 앞서 확인한 더하기 연산을 응용해 여러 구성 요소로 이루어진 CoroutineContext 객체들을 합칠 수 있음
부연 설명
- coroutineContext1에 있는 모든 CoroutineContext 구성 요소가 coroutineContext2에 있기 때문에 모든 구성 요소가 덮어씌워졌지만 만약 coroutineContext1에 coroutineContext2에 없는 Job 객체인 sampleJob이 추가로 있었다면 sampleJob은 덮어씌워지지 않고 남음
CoroutineContext 구성 요소에 접근하기
- CoroutineContext 객체의 구성 요소에 접근하기 위해서는 각 구성 요소가 가진 고유한 키가 필요
- 따라서 각 구성 요소의 키를 얻는 방법을 아는 것이 중요
1. CoroutineContext 구성 요소의 키
- CoroutineContext 구성 요소의 키는 CoroutineContext.Key 인터페이스를 구현해 만들 수 있는데 일반적으로 CoroutineContext 구성 요소는 자신의 내부에 키를 싱글톤 객체로 구현
- ex) CoroutineName 클래스 내부에 CoroutineContext.Key<CoroutineName>을 구현하는 동반 객체 Key가 있는 것을 확인 가능
- CoroutineContext 구성 요소의 내부에 선언된 키는 다음과 같음
- CoroutineName - CoroutineName.Key
- Job - Job.Key
- CoroutineDispatcher - CoroutineDispatcher.Key
- CoroutineExceptionHandler - CoroutineExceptionHandler.Key
2. 키를 사용해 CoroutineContext 구성 요소에 접근하기
2.1 싱글톤 키를 사용해 CoroutineContext 구성 요소에 접근하기
- 앞서 설명했다시피 CoroutineName.Key를 사용해 CoroutineContext 객체의 CoroutineName 구성 요소에 접근 가능
- get은 연산자 함수이기 때문에 대괄호로 대체 가능
2.2 구성 요소 자체를 키로 사용해 구성 요소에 접근하기
- CoroutineContext의 주요 구성 요소인 CoroutineName, Job, CoroutineDispatcher, CoroutineExceptionHandler 객체는 동반 객체로 CoroutineContext.Key를 갖고 있기 때문에 Key를 명시적으로 사용하지 않고 구성 요소 자체를 키로 사용 가능
2.3 구성 요소의 key 속성을 사용해 구성 요소에 접근하기
- CoroutineContext 구성 요소들은 모두 key 속성을 가지며 이를 사용해 구성 요소에 접근 가능
CoroutineContext 구성 요소 제거하기
- CoroutineContext 객체는 구성 요소를 제거하기 위한 minusKey 함수도 제공
- minusKey 함수는 구성 요소의 키를 인자로 받아 해당 구성 요소를 제거한 CoroutineContext 객체를 반환
1. minusKey 사용해 구성 요소 제거하기
2. minusKey 함수 사용 시 주의 사항
- minusKey 함수 사용 시 주의할 점은 minusKey를 호출한 CoroutineContext 객체는 그대로 유지되고, 구성 요소가 제거된 새로운 CoroutineContext 객체가 반환된다는 것
- 따라서 기존 객체의 CoroutineName 속성으로 접근할 경우 null이 아닌 MyCoroutine이 출력되는 것을 확인 가능
참고
코틀린 코루틴의 정석 (조세영 저)
'Kotlin > 코틀린 코루틴의 정석' 카테고리의 다른 글
[Kotlin 코루틴] 예외 처리 (0) | 2024.11.22 |
---|---|
[Kotlin 코루틴] 구조화된 동시성 (0) | 2024.11.21 |
[Kotlin 코루틴] async와 Deferred (0) | 2024.11.15 |
[Kotlin 코루틴] 코루틴 빌더와 Job 정리 (0) | 2024.11.08 |
[Kotlin 코루틴] CoroutineDispatcher 정리 (1) | 2024.11.05 |