Juyae
Posted on June 16, 2021
Coroutine
Coroutine은 Thread/ AsyncTask/Rx 작업을 대신할 수 있는 Asynchronous/Non-Blocking Programming을 제공하는 Light-Weight Threads 로 가볍고 유연한 병렬 프로그래밍을 위한 기술
Kotlin 코루틴으로 앱 성능 향상
코루틴을 왜 사용할까 ? 크게 5가지로 알아보자
1.비동기 코드 작성
- 네트워크 호출이나 디스크 작업과 같은 장기 실행 작업을 관리하면서 앱의 응답성을 유지하는 깔끔하고 간소화된 비동기 코드 작성 가능
2.장기 실행 작업 관리
- 장기 실행 작업을 처리하는 두 작업을 추가하여 일반 함수를 기반으로 빌드
- invoke 및 return 외에도 suspend 및 resume 추가
3.스택 프레임
- 로컬 변수와 함께 실행 중인 함수 관리
- Coroutine 정지하면 현재 스택 프레임이 복사되고 저장되어 재개될 시 저장된 위치에서 다시 복사되고 실행
- 일반적인 순차 차단 요청처럼 보일 수도 있지만 네트워크 요청이 기본 스레드를 차단하지 않도록 함
4.기본 안전
- Kotlin에서 모든 코루틴은 기본 스레드에서 실행 중인 경우에도 디스패처에서 실행
-
Kotlin에서 자체적 정지될 수 있으며 디스패처는 Coroutine 재개를 담당
- Dispatchers.Main - 이 디스패처를 사용하여 기본 Android 스레드에서 코루틴을 실행합니다. 이 디스패처는 UI와 상호작용하고 빠른 작업을 실행하기 위해서만 사용해야 합니다. 예를 들어
suspend
함수를 호출하고 Android UI 프레임워크 작업을 실행하며LiveData
객체를 업데이트함 - Dispatchers.IO - 이 디스패처는 기본 스레드 외부에서 디스크 또는 네트워크 I/O를 실행하도록 최적화되어 있음 예를 들어 회의실 구성요소를 사용하고 파일에서 읽거나 파일에 쓰며 네트워크 작업을 실행
- Dispatchers.Default - 이 디스패처는 CPU를 많이 사용하는 작업을 기본 스레드 외부에서 실행하도록 최적화되어 있습니다. 예를 들어 목록을 정렬하고 JSON을 파싱
- Dispatchers.Main - 이 디스패처를 사용하여 기본 Android 스레드에서 코루틴을 실행합니다. 이 디스패처는 UI와 상호작용하고 빠른 작업을 실행하기 위해서만 사용해야 합니다. 예를 들어
5.Background Task가 필요한 대표적인 경우
- 네트워크 Request (Retrofit, OkHttp3, UrlConnection 등)
- 내부 DataBase (Room, SQLite 등)
Thread와 차이점
Thread
Coroutine
Coroutine은 즉시 실행하는게 아니며, Thread와 다르게 OS의 영향을 받지않기 때문에 그만큼의 비용 절약
Coroutine 전환 시 Context Switch가 발생하지 않음
개발자가 직접 루틴을 언제 실행할지, 언제 종료할지 모두 지정이 가능
-
이렇게 생성한 루틴은 작업 전환 시에 시스템의 영향을 받지 않아, 그에 따른 비용이 발생하지 않음
CoroutineScope& GlobalScope
- CoroutineScope는 코루틴의 범위, 블록을 묶음으로 제어할 수 있는 단위
- GlobalScope는 CoroutineScope의 한 종류로 Top-level Coroutine, Application의 생명주기에 종속적으로 존재
CoroutineContext
- CoroutineContext는 코루틴을 어떻게 처리할 것인지에 대한 정보 집합 , 주요 요소로는 Job & Dispatcher 존재
Dispatcher
- Dispatcher는 CoroutineContext의 주요 요소
- 위에서 말했던 CoroutineContext를 상속 받아 어떤 스레드를 어떻게 동작할 것인가에 대한 정의
Coroutine 권장사항
디스패처 삽입
새 코루틴을 만들거나 withContext 를 호출할 때 Dispatchers 를 하드코딩 하지 말 것
// DO inject Dispatchersclass NewsRepository( private val defaultDispatcher: CoroutineDispatcher = Dispatchers.Default) { suspend fun loadNews() = withContext(defaultDispatcher) { /* ... */ }}// DO NOT hardcode Dispatchersclass NewsRepository { // DO NOT use Dispatchers.Default directly, inject it instead suspend fun loadNews() = withContext(Dispatchers.Default) { /* ... */ }}
정지 함수는 기본 스레드에서 호출하기에 안전해야 함
정지 함수는 기본 스레드에서 호출하기에 안전한 기본 안전 함수여야 함
다음과 같은 패턴을 통해 앱의 확장 가능성이 높아지는데
이는 정지 함수를 호출하는 클래스가 작업 유형에 어떤 Dispatcher 를 사용할 지 걱정할 필요가 없음 . 작업을 실행하는 클래스에 책임이 있음
ViewModel은 코루틴을 만들어야 함
- 뷰는 코루틴을 직접 트리거하여 비즈니스 로직을 실행하면 안 되고 이 책임을 ViewModel에 맡겨 비즈니스 로직을 더 쉽게 테스트 가능
- 또한 작업이 viewModelScope에서 시작되면 코루틴이 구성 변경에도 자동 유지
예외에 주의
- 코루틴에서 발생하는 예외를 잘못 처리하면 앱이 비정상 종료 될 수 있음 따라서 다음과 같은 코드로 예외를 포착
Conclusion
위의 내용을 정리하면서 코루틴에 대한 전반적인 이론을 알아봤다.
다음 글에서는 코루틴을 적용한 예시 코드로 실습하려고 한다.
Posted on June 16, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 21, 2024