일시 중단 함수와 코루틴
1. 일시 중단 함수란?
- 주로 코루틴의 비동기 작업과 관련된 복잡한 코드들을 구조화하고 재사용할 수 있는 코드의 집합으로 만드는 데 사용
- `suspend fun` 키워드로 선언되는 함수로 함수 내에 일시 중단 지점을 포함할 수 있는 특별한 기능을 수행함
- 일시 중단 지점"은 코루틴(coroutine) 내에서 실행이 일시적으로 중단될 수 있는 지점을 의미
- ex) delay 함수의 경우 일시 중단 지점을 포함하므로 일반 함수는 delay 함수가 포함시킬 수 없고 오직 suspend fun 함수만 delay 함수를 포함시킬 수 있음
2. 일시 중단 함수는 코루틴이 아니다
- 일시 중단 함수는 코루틴 내부에서 실행되는 코드의 집합일 뿐, 코루틴이 아님
- 일시 중단 함수는 기존의 함수와 똑같은 재사용이 가능한 코드 블록
- 만약 일시 중단 함수를 코루틴처럼 사용하고 싶을 경우 일시 중단 함수를 코루틴 빌더로 감싸야함
3. 일시 중단 함수를 별도의 코루틴 상에서 실행하기
- 앞서 언급했다시피 일시 중단 함수를 새로운 코루틴에서 실행하고 싶을 경우 일시 중단 함수를 코루틴 빌더 함수로 감싸면 됨
부연 설명
- launch 함수가 호출돼 생성된 코루틴들은 실행되자마자 delayAndPrintHelloWorld 함수의 호출로 1초간 쓰레드 사용 권한을 양보함
- 자유로워진 쓰레드는 다른 코루틴인 runBlocking 코루틴에 의해 사용될 수 있으므로 곧바로 마지막 줄의 getElapsedTime이 실행됨
- 따라서 코드의 실행 결과를 보면 지난 시간이 약 0초에 가까운 것을 확인할 수 있으며 이후 1초 정도 지나고 나서 재개된 코루틴들에 의해 `Hello World` 문자열이 두 번 출력됨
일시 중단 함수의 사용
- 일시 중단 함수는 내부에 일시 중단 가능 지점을 포함할 수 있기 때문에 일시 중단 할 수 있는 곳에서만 호출 가능
- 코틀린에서 일시 중단이 가능한 지점은 다음과 같이 두 가지
- 코루틴 내부
- 일시 중단 함수
- 코틀린에서 일시 중단이 가능한 지점은 다음과 같이 두 가지
1. 코루틴 내부에서 일시 중단 함수 호출하기
- 일시 중단 함수는 코루틴의 일시 중단이 가능한 작업을 재사용이 가능한 블록으로 구조화할 수 있도록 만들어진 함수
- 코루틴은 언제든지 일시 중단 함수를 호출할 수 있음
2. 일시 중단 함수에서 다른 일시 중단 함수 호출하기
- 일시 중단 함수는 또 다른 일시 중단 함수에서 호출될 수 있음
부연 설명
- searchByKeyword 일시 중단 함수는 searchFromDB와 searchFromServer를 호출하며, 결과로 받은 값들을 합쳐 반환
- 위에서 거론된 함수들은 모두 일시 중단 함수들이며 searchFromDB와 searchFromServer 내부의 delay(1000L)로 인해 1초간 일시 중단돼 결괏값을 반환하는 데 1초 정도 걸림
3. 일시 중단 함수에서 코루틴 실행하기
- launch나 async 같은 코루틴 빌더 함수는 CoroutineScope의 확장 함수로 선언되어 있음
- 따라서 일시 중단 함수에서 launch나 async 같은 코루틴 빌더 함수를 호출하기 위해서는 일시 중단 함수 내부에서 CoroutineScope 객체에 접근할 수 있어야 함
- coroutineScope 일시 중단 함수를 사용하면 일시 중단 함수 내부에 새로운 CoroutineScope 객체를 생성할 수 있음
- coroutineScope는 구조화를 깨지 않는 CoroutineScope 객체를 생성하며 생성된 CoroutineScope 객체는 coroutineScope의 block 람다식에서 수신 객체(this)로 접근 가능
부연 설명
- async 코루틴 빌더를 사용해 searchFromDB를 실행하는 코루틴인 dbResultsDeferred와 searchFromServer를 실행하는 코루틴인 serverResultsDeferred를 생성하고, 결과가 반환되는 부분에서 await를 호출해 searchFromDB와 searchFromServer 작업이 함께 실행될 수 있도록 처리
- 핵심은 searchByKeywordAsync 일시 중단 함수가 호출됐을 때 코루틴이 다음과 같이 구조화된다는 것
- runBlocking 코루틴에서 searchByKeyword 일시 중단 함수를 호출하면 내부에서 coroutineScope 함수를 통해 새로운 Job 객체를 가진 CoroutineScope 객체가 생성됨
- 그 자식으로 데이터베이스와 서버로부터 데이터를 가져오는 코루틴이 각각 생성됨
- 따라서 코드를 실행해 보면 searchFromDB 작업과 searchFromServer 작업이 서로 다른 코루틴에서 실행돼 1초 정도 만에 실행 완료되는 것을 확인 가능
4. supervisorScope 사용해 일시 중단 함수에서 코루틴 실행하기
- 3번 코드에 한 가지 문제가 존재함
- 데이터베이스에서 데이터를 조회하는 코루틴이 오류를 발생시키면 부모 코루틴으로 오류를 전파해 서버에서 데이터를 조회하는 코루틴까지 취소될 수 있음
- 심지어 일시 중단 함수를 호출한 코루틴에까지 예외가 전파돼 호출부의 코루틴까지 모두 취소됨
- supervisorScope 일시 중단 함수를 통해 위 문제를 해결할 수 있음
부연 설명
- dbResultsDeferred 코루틴에서 예외가 발생해 해당 코루틴이 취소되더라도 부모로 supervisorScope를 통해 생성되는 SupervisorJob 객체를 가지므로 예외가 부모 코루틴으로 전파되지 않는 것을 확인 가능
참고
코틀린 코루틴의 정석 (조세영 저)
반응형
'Kotlin > 코틀린 코루틴의 정석' 카테고리의 다른 글
[Kotlin 코루틴] 코루틴 심화 (1) | 2024.11.29 |
---|---|
[Kotlin 코루틴] 코루틴의 이해 (0) | 2024.11.26 |
[Kotlin 코루틴] 예외 처리 (0) | 2024.11.22 |
[Kotlin 코루틴] 구조화된 동시성 (0) | 2024.11.21 |
[Kotlin 코루틴] CoroutineContext 정리 (0) | 2024.11.19 |