Kotlin

Kotlin Coroutines(1)

smomo 2021. 5. 22. 10:25

코루틴, Coroutines?

Coroutines = Co + Routines

Co는 협력을 Routines는 function을 의미한다.

Kotlin Coroutines 특징

  • Asynchronous
  • Cooperative multitasking
  • Single-threaded
  • Non-blocking

 

이미지 출처 https://www.slideshare.net/BartomiejOsmaek/kotlin-coroutines-the-new-async

기본 개념

CoroutineScope

코루틴의 범위, 코루틴 블록을 묶음으로 제어할수 있는 단위

launch 또는 async를 사용하여 생성한 모든 코루틴을 추적한다.

(launch, async는 CoroutineScope의 확장 함수)

실행중인 코루틴은 언제든지 scope.cancel()을 호출하여 취소할 수 있다.

 

Android와 같은 일부 플랫폼에는 이미 viewModelScope, lifecycleScope와 같은 특정 라이프사이클 클래스에 CoroutineScope를 제공하는 KTX 라이브러리가 있다.

 

CoroutineScope를 만들 때 생성자에 대한 매개 변수로 CoroutineContext를 사용한다. 

// Job and Dispatcher are combined into a CoroutineContext 
val scope = CoroutineScope(Job() + Dispatchers.Main)
val job = scope.launch {
    // new coroutine
}

CoroutineScope를 사용하여 새 코루틴을 만드는 것외에 코루틴 내부에 코루틴을 생성할 수 있다.

val scope = CoroutineScope(Job() + Dispatchers.Main)
val job = scope.launch {
    // New coroutine that has CoroutineScope as a parent
    val result = async {
        // New coroutine that has the coroutine started by 
        // launch as a parent
    }.await()
}

GlobalScope

CoroutineScope의 한 종류. Application이 종료될 때까지 코루틴을 실행시킬 수 있다.

(만일 Activity에서 코루틴을 GlobalScope영역에서 실행시켰다면, Activity가 종료되어도 코루틴은 작업이 끝날 때까지 동작한다.)

Job

코루틴에 대한 handle
생성하는 모든 코루틴에 대해 코루틴을 고유하게 식별하고 라이프 사이클을 관리하는 Job Instance를 반환한다.

Job을 CoroutineScope에 전달하여 수명주기에 대한 핸들을 유지할 수도 있다.

CoroutineContext

코루틴을 어떻게 처리할 것인지에 대한 여러가지 정보의 집합

CoroutineContext 의 주요 요소로는 Job, CoroutineDispatcher, CoroutineExceptionHandler가 있다. 

Dispatcher

CoroutineContext를 상속받아 어떤 스레드를 어떻게 동작할 것인가에 대한 미리 정의

Dispatchers.Default : 메인 스레드에서 CPU 집약적인 작업에 최적화

 - Sorting a list 
 - Parsing JSON 
 - DiffUtils

Dispatchers.IO : 메인 스레드의 디스크 및 네트워크 IO에 최적화  

 - Database 
 - Reading/writing files 
 - Networking

Dispatchers.Main : 안드로이드의 경우 UI 스레드를 사용한다.

 - Calling suspend functions

 - Call UI functions 
 - Updating LiveData

Job Lifecycle

 

코루틴이 Active 상태인 경우 코루틴이 실패하거나 job.cancel()을 호출하면 작업이 Cancelling 상태 (isActive = false, isCancelled = true)로 이동한다. 모든 children이 작업을 완료하면 코루틴은 Canceled 상태가 되고 isCompleted = true가 된다.

Parent CoroutineContext

Parent context = Defaults + inherited CoroutineContext + arguments

+ 연산자를 사용하여 CoroutineContext를 결합할 수 있다.

E.g. (Dispatchers.Main, “name”) + (Dispatchers.IO) = (Dispatchers.IO, “name”)

 

New coroutine context = parent CoroutineContext + Job()

 

위 이미지에 표시된 CoroutineScope를 사용하여 다음과 같은 새 코루틴을 만든다.

val job = scope.launch(Dispatchers.IO) {
    // new coroutine
}

CoroutineContext와 Parent Context의 Job은 동일한 인스턴스가 될 수 없다.

References