코루틴 빌더와 Job 객체 개요
- 코루틴을 생성하는 데 사용하는 함수
- ex) runBlocking, launch
- 모든 코루틴 빌더 함수는 코루틴을 만들고 코루틴을 추상화한 Job 객체를 생성
- 코루틴은 일시 중단할 수 있는 작업으로 실행 도중 일시 중단된 후 이후 이어서 실행될 수 있음
- 코루틴을 추상화한 Job 객체는 이에 대응해 코루틴을 제어할 수 있는 함수와 코루틴의 상태를 나타내는 상태 값들을 외부에 노출시킴
부연 설명
- launch 함수 호출 시 코루틴 생성
- Job 객체가 생성되고 반환되는 것을 확인 가능
join을 사용한 코루틴 순차 처리
- Job 객체는 순차 처리가 필요한 상황을 위해 join 함수를 제공
- join 함수를 통해 먼저 처리되어야 하는 코루틴의 실행이 완료될 때까지 호출부의 코루틴을 일시 중단하도록 만들 수 있음
부연 설명
- runBlocking 코루틴이 updateTokenJob.join()을 호출하면 runBlocking 코루틴은 updateTokenJob 코루틴이 완료될 때까지 일시 중단됨
- join 함수를 호출하지 않을 경우 `토큰 업데이트 작업`과 `네트워크 요청 작업`이 병렬로 동시에 실행됐음
joinAll을 사용한 코루틴 순차 처리
- 실제 개발에서는 서로 독립적인 여러 코루틴을 병렬로 실행한 뒤 실행한 요청들이 모두 끝날 때까지 대기한 뒤 다음 작업을 진행하는 것이 효율적
- 이를 위해 Job 객체는 joinAll 함수를 제공하며 joinAll 함수는 가변 인자로 Job 타입의 객체를 받은 후 각 Job 객체에 대해 모두 join 함수를 호출하는 것이 전부
CoroutineStart.LAZY를 통해 코루틴 지연
- launch 함수를 사용해 코루틴을 생성하면 유휴 쓰레드가 있는 경우 곧바로 실행되지만 나중에 실행돼야 할(지연 시작) 코루틴을 미리 생성해야 하는 케이스도 존재
- 코루틴을 지연 시작하기 위해서는 launch 함수의 start 인자로 CoroutineStart.LAZY를 넘겨 코루틴에 지연 시작 옵션을 적용해야 함
- 지연 코루틴은 명시적으로 실행을 해줘야 함
- Job 객체의 start 함수를 명시적으로 호출해야 함
코루틴 취소하기
- 코루틴 실행 도중 코루틴을 실행할 필요가 없어질 경우 즉시 취소해야 함
- 필요 없는 코루틴을 실행되도록 두면 코루틴을 계속해서 쓰레드를 점유하며 성능 저하를 유발할 수 있음
- 위 문제를 해결하기 위해 Job 객체는 코루틴을 취소할 수 있는 cancel 함수를 제공
1. cancel 함수를 사용해 Job 취소하기
2. cancelAndJoin을 사용한 순차 처리
- Job 객체에 cancel 함수를 호출하면 코루틴은 즉시 취소되는 것이 아니라 Job 객체 내부의 취소 확인용 flag 변수를 `취소 요청됨`으로 변경함으로써 코루틴이 취소돼야 한다는 것만 알림
- 이후 미래의 어느 시점에 코루틴의 취소가 요청됐는지 체크하고 취소됨
- 앞서 Job 객체의 join 함수를 사용하면 코루틴을 순차 처리할 수 있었던 것처럼 cancelAndJoin 함수를 사용하면 취소에 대한 순차 처리가 가능해짐
3. 코루틴의 취소가 확인되는 시점
- 코루틴은 일반적으로 실행 대기 시점이나 일시 중단 시점에 취소를 확인한 후 취소됨
- while 문을 통해 무한 루프를 실행할 경우 일시 중단 지점이 없기 때문에 일시 중단이 일어날 수 없음
- 위 문제를 해결할 수 있는 세 가지 방법 존재
- delay를 사용한 취소 확인
- yield를 사용한 취소 확인
- CoroutineScope.isActive를 사용한 취소 확인
3.1 delay를 사용한 취소 확인
- delay 함수는 일시 중단 함수(suspend fun)로 선언돼 특정 시간만큼 호출부의 코루틴을 일시 중단시킴
- 앞서 언급했듯이 코루틴은 일시 중단되는 시점에 코루틴의 취소를 확인
- 목적은 달성하지만 불필요하게 작업을 일시 중단시키므로 성능 저하 유발함
3.2 yield를 사용한 취소 확인
- yield 함수가 호출되면 코루틴은 자신이 사용하던 쓰레드를 양보함
- 쓰레드 사용을 양보한다는 것은 쓰레드 사용을 중단한다는 뜻이므로 yield를 호출함으로써 목적 달성 가능
- 하지만 yield 함수 또한 while 문을 한 번 돌 때마다 쓰레드 사용이 양보되면서 일시 중단되는 문제가 발생해 비효율적
3.3 CoroutineScope.isActive를 사용한 취소 확인
- CoroutineScope는 코루틴이 활성화됐는지 확인할 수 있는 Boolean 타입의 프로퍼티인 isActive를 제공함
- 코루틴에 취소가 요청되면 isActive 프로퍼티의 값은 false로 바뀜
- 위 방법을 사용하면 코루틴이 잠시 멈추지도 않고 쓰레드 사용을 양보하지 않으면서 계속해서 작업을 할 수 있어 효율적
코루틴의 상태와 Job의 상태 변수
- 코루틴은 6가지 상태를 가짐
- 생성 (New)
- 실행 중 (Active)
- 실행 완료 중 (Completing)
- 실행 완료 (Completed)
- 취소 중 (Cancelling)
- 취소 완료 (Cancelled)
- 이 중 `실행 완료 중` 상태는 이번 게시글 말고 이후 게시글에 다룰 예정
1. Job 객체에서 외부로 공개하는 코루틴의 상태 변수
- Job 객체의 상태 변수들은 코루틴의 상태마다 변화함
- 외부로 공개하는 코루틴의 상태 변수는 총 세 가지로 모두 Boolean 타입
- isActive
- isCancelled
- isCompleted
1.1 isActive
- 코루틴이 활성화돼 있는지의 여부 확인 가능
- 코루틴이 활성화돼 있으면 true
- 활성화돼 있지 않으면 false
1.2 isCancelled
- 코루틴이 취소 요청됐는지의 여부 확인 가능
- 코루틴에 취소 요청되면 true
- 앞서 언급했다시피 isCancelled가 참이더라도 즉시 취소되는 것은 아님
1.3 isCompleted
- 코루틴 실행이 완료됐는지의 여부 확인 가능
- 코루틴의 모든 코드가 실행 완료되면 true 반환
- 혹은 취소 완료되면 true 반환
- 실행 중인 상태에서는 false
2. 코루틴 상태
2.1 생성 (New)
- 코루틴 빌더를 통해 코루틴을 생성하면 코루틴은 기본적으로 생성 상태
- 보통 자동으로 `실행 중` 상태로 넘어감
- 앞서 언급한 CoroutineStart.LAZY를 start 인자로 넘기면 실행 중 상태로 바로 안 바뀜
2.2 실행 중 (Active)
- 코루틴이 실제로 실행 중일 때뿐만 아니라 실행된 후 일시 중단된 때도 실행 중 상태
2.3 실행 완료 (Completed)
- 코루틴의 모든 코드가 실행 완료된 상태
2.4 취소 중 (Cancelling)
- Job.cancel() 등을 통해 코루틴에 취소가 요청됐을 경우 최소 중 상태로 넘어감
- 아직 취소된 상태가 아니어서 코루틴은 계속해서 실행됨
2.5 취소 완료 (Cancelled)
- 코루틴의 취소 확인 시점에 취소가 확인된 경우 취소 완료 상태로 전환
- 해당 상태에서는 코루틴은 더 이상 실행되지 않음
3. 코루틴 상태 정리
코루틴 상태 | isActive | isCancelled | isCompleted |
생성 (New) | false | false | false |
실행 중 (Active) | true | false | false |
실행 완료 (Completed) | false | false | true |
취소 중 (Cancelling) | false | true | false |
취소 완료 (Cancelled) | false | true | true |
참고
코틀린 코루틴의 정석 (조세영 저)
반응형
'Kotlin > 코틀린 코루틴의 정석' 카테고리의 다른 글
[Kotlin 코루틴] 예외 처리 (0) | 2024.11.22 |
---|---|
[Kotlin 코루틴] 구조화된 동시성 (0) | 2024.11.21 |
[Kotlin 코루틴] CoroutineContext 정리 (0) | 2024.11.19 |
[Kotlin 코루틴] async와 Deferred (0) | 2024.11.15 |
[Kotlin 코루틴] CoroutineDispatcher 정리 (1) | 2024.11.05 |