일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
Tags
- Next Challenge
- 백준
- 백준2309
- coroutine
- conflate
- withContext
- monotone stack
- Product Flavor
- cancellationException
- hotStream
- google play console
- ServerDrivenUI
- TOSS 과제
- Algorithm
- 안드로이드
- flowon
- KAKAO
- coldStream
- java
- Advanced LCA
- SDUI
- coroutinescope
- 릴리즈 키해시
- Kotlin
- collectLatest
- Android
- coroutinecontext
- ShapeableImageView
- app-distribution
- Flow
Archives
- Today
- Total
루피도 코딩한다
[Coroutine Basics 4] Coroutine Cacelation 본문
코루틴 취소를 왜하냐?
- 필요하지 않은 코루틴을 적절히 취소해 컴퓨터 자원을 아낄 수 있다
코루틴 취소 하는 방법 == CancellationException 발생
- Kotlin 공식문서의 말을 빌리자면 *' A coroutine code has to cooperate to be cancellable' *라고 한다.
- Cancellable 하다라는 것은 코루틴 블록 내부에서
CancellationException
이 발생가능한 구조여야 한다는 것이다. CancellationException
이 발생되는 방법은 아래와 같이 두가지가 있다.
[취소 방법 1] kotlinx.coroutines
의 suspending function을 활용하자
kotlinx.coroutines
의 suspending 함수들은 'cancellable'하다고 적혀있다.
== 내부적으로 'CancellationException' 발생시킴- 예시로는
delay()
,yield()
와 같은 함수들이 있다 delay()
함수의 내부 구현을 보면, 현재 코루틴의 Job 상태가 canceled되었거나 completed 되었다면 CancellationException이 발생한다고 적혀있다 (아래 이미지 참고)- Waiting 상태에서 외부에서 cancel을 호출하면 CancellationException()이 발생되고 취소됨
- 해당 job이 completed상태여도 CancellationException이 발생함. 그러니 이미 coroutine의 job이 완료가 된 상황에서 외부에서 cancel 코드를 호출하면 아무일도 일어나지 않는다는건 자명한 사실~
아니 그러면 delay(),
yeild()
같은거 안쓸때는 코루틴 취소를 어떻게 해야하냐???
- 위 코드 블록을 통해 코루틴 내부에서 kotlinx.coroutines의 suspending 함수가 없는 경우, 코루틴 외부에서 cancel()시키더라도 코루틴이 취소되지 않는다는 것을 알 수 있다.
- main에서 cancelAndJoin()이라는 job을 취소하고 완료될때까지 기다리는 함수를 호출했음에도 불구하고 coroutine은 취소되지 않고
job: I'm sleeping 5 ...
까지 while문을 야무지게 끝까지 실행한다.
[취소 방법 2] 코루틴이 셀프로 자기 상태를 확인하고, 취소 요청을 받았다면 CancellationException
던지기
코루틴 내부에서 isActive라는 boolean 확장 프로퍼티에 접근 가능한데, 이 프로퍼티를 확인함으로써 취소 요청을 받았는지 안받았는지 확인할 수 있다. (isActive가 false이면 취소 요청을 받은거임 ㅎ)
그리고 취소 요청을 받았다면, Kotlinx.Coroutines
내부 suspend 함수들처럼 셀프로 CancellationException
을 던지는 것이다.
따라서 위 코드 블록에서 while()문 내부에 if(!isActive)
라면 throw CanellationException()
을 던지코드를 추가해보도록 하자
// 코루틴 셀프 취소 방법 1
while() {
if (!isActive) {
throw CancellationException()
}
// 실행할 코드들..
}
// 코루틴 셀프 취소 방법 2
while(isActive){
// 실행할 코드들..
}
// cf. isActive는 아래와 같이 CoroutineScope.kt 내부에 확장 프로퍼티로 정의되어 있음
public val CoroutineScope.isActive: Boolean
get() = coroutineContext[Job]?.isActive ?: true
- 자 그럼 위 코드 블록에서 isActive에 따른 처리만 해주면 코루틴 취소가 될까?
- 원래 이런 질문은 안되니까 물어보는게 국룰~
- 현재 runBlocking 내부의 코드는 main thread 하나에서만 실행되고 있다.
(Dispatcher 따로 지정 안함 == 스레드풀 수동으로 지정 안함 == 메인스레드에서 다 실행됨) - launch로 시작하는 코루틴 코드는 일단 실행되지 않고 일단 pass
- launch 블록 밑에 delay()를 만남 -> 양보가 일어나면서 launch 실행
- launch 끝나야 cancel() 이 호출됨 (위 이미지 타임라인 참고)
- 현재 runBlocking 내부의 코드는 main thread 하나에서만 실행되고 있다.
- 그러면 어떻게 가능하게 만들까?
- launch 내부에 코루틴이 실행되는 '도중에' cancel()을 호출해야됨
- '도중에'가 가능하려면 스레드 두개를 사용해서 동시에 동작시켜야함
- 따라서
lanuch(Dispatchers.Default){}
이렇게 launch로 코루틴을 시작시킬때 다른 스레드에서 동작시키게끔 정해주는것이다 - Dispatchers 종류 by GPT
- *Dispatchers.Default: *기본 스레드 풀을 사용하여 CPU 바운드 작업을 처리합니다. 주로 CPU 작업에 사용됩니다.
- Dispatchers.IO: I/O 작업을 처리하기 위한 디스패처입니다. 파일 읽기/쓰기, 네트워크 호출과 같은 블로킹 I/O 작업에 적합합니다.
- Default를 썼을 때와 마찬가지로 잘 cancel된다
- Dispatchers.Main: Android 및 JavaFX와 같은 UI 스레드에서 사용하기 위한 디스패처입니다. 주로 UI 업데이트와 관련된 작업에 사용됩니다.
- Android 및 JavaFX의 환경에서만 사용한 Thread풀인듯하다. android dependecy가 없는 kt 파일에서 실행시키니 에러가 난다
- *Dispatchers.Unconfined: *디스패처를 지정하지 않은 경우, 현재 실행 중인 코루틴과 동일한 스레드에서 실행됩니다. 하지만 일시 중지 및 재개되는 동안 스레드가 변경될 수 있습니다.
- 위 코드에서 스레드풀을 Unconfined로 지정해주게 되면 메인 스레드에서만 동작하게 되므로 코루틴 취소가 일어나지 않는다
- Dispatchers.Main.immediate: Android에서만 사용 가능한 특별한 디스패처로, 즉시 작업을 실행합니다. 일반적인
Dispatchers.Main
과 유사하지만, 즉시 실행됩니다. Dispatchers.kt
내부에 아래와 같이 CoroutineDispatcher를 구현한 객체들이 정의돼어 있다.actual
이라는 키워드 선언을 통해 각 플랫폼에 맞는 실제 구현이 제공되는 구조라고 한다. (actual 키워드가 expect 선언에 대응되어 사용되며, KMP와 관련있는 개념이다 Kotlin Docs)
정리하자면
isActive()
: 현재 코루틴이 활성화 되어 있는지, 취소 신호를 받았는지 확인Dispatchers.Default
: 코루틴을 다른 스레드에 배정
두개의 스레드를 동시에 이용함으로써 Cacel을 시키는 구조이다.
'Cancellation is cooperative' 이제는 이 말을 이해할 수 있다
이렇게 코루틴 내부에서 CancellationException()이 발생되어야만 취소가 가능하며, 이를 '협력'해야 취소가 가능하다라는 말로도 나타내는듯 하다.
CacellationException()와 try-catch-finally
- 만약 try에서
CacellationException()
이 발생했는데,catch( e: CancellationExcpetion)
에서 Exception을 잡아버리면 어떻게 될까? 당연히 취소 되지 않는다! - 주로 의도가 있어서 cancel을 작동시켰을 테니까 catch 문은 작성을 안하는게 일반적인듯 하고
- 대신, finally 에서 필요한 작업을 처리하는 방법이 있다고 한다.
끝!
'Coroutine' 카테고리의 다른 글
[Coroutine Basics 6] Structured Concurrency, CoroutineScope, CoroutineContext (0) | 2024.01.22 |
---|---|
[Coroutine Basics 5] 코루틴의 예외 처리와 Job의 상태 변화 (1) | 2024.01.21 |
[Coroutine Basics 3] Coroutine Builder and Job (0) | 2024.01.18 |
[Coroutine Basics 2] Android에서의 Thread와 Coroutine (0) | 2024.01.17 |
[Coroutine Basics 1] Routine과 Coroutine의 개념과 예시 (0) | 2024.01.11 |
Comments