코틀린 코루틴의 기초

GM.Lim
6 min readMay 24, 2019

--

Photo by Randy Fath on Unsplash

코틀린 의 코루틴은 비동기 프로그래밍을 처리할수 있는 좋은 방법입니다.

코루틴을 사용하면 어떠한 작업을 foreground (전경) 에서 background (배경) 으로 또는 그 반대로 쉽게 전환하면서 처리할수 있습니다.

코루틴에 대한 관심이 높아지면서 많은 글에서 다루고 있지만 명확하게 정리된 글을 찾는것은 어렵습니다.

우선 코루틴의 주요 내용을 최대한 쉽게 정리하고 차후 안드로이드 에서의 코루틴 사용법을 알아보고자 합니다.

1. 주요 핵심 키워드

코루틴을 사용하기 위해서 기본적으로 알아야 할 주요 키워드는 아래와 같습니다.

- CoroutineScope (그리고 GlobalScope)
- CoroutineContext
- Dispatcher
- launch (그리고 async)

CoroutineScope

CoroutineScope 는 말 그대로 코루틴의 범위, 코루틴 블록을 묶음으로 제어할수 있는 단위입니다.

GlobalScope 는 CoroutineScope 의 한 종류입니다. 미리 정의된 방식으로 프로그램 전반에 걸쳐 백그라운드 에서 동작합니다.

CoroutineContext

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

CoroutineContext 의 주요 요소 로는 Job 과 dispatcher 가 있습니다.

Dispatcher

Dispatcher 는 CoroutineContext 의 주요 요소 입니다.

CoroutineContext 을 상속받아 어떤 스레드를 이용해서 어떻게 동작할것인지를 미리 정의해 두었습니다.

다음은 io’19 세션 Understand Kotlin Coroutines on Android 에서 설명된 Dispatcher 의 용도 입니다.

Dispatchers.Default : CPU 사용량이 많은 작업에 사용합니다. 주 스레드에서 작업하기에는 너무 긴 작업 들에게 알맞습니다.Dispatchers.IO : 네트워크, 디스크 사용 할때 사용합니다. 파일 읽고, 쓰고, 소켓을 읽고, 쓰고 작업을 멈추는것에 최적화되어 있습니다.Dispatchers.Main : 안드로이드의 경우 UI 스레드를 사용합니다.

Dispatchers.Main 은 UI 구성하는 스레드를 메인으로 사용 하는 플랫폼에서 사용됩니다.

대표적으로 안드로이드 의 경우 메인 스레드는 UI 스레드 이고, 안드로이드에서 Dispatchers.Main 은 UI 스레드를 사용하여 동작합니다.

Dispatchers.Main 을 사용할수 없는 플랫폼도 있으며 이러한 플랫폼에서 사용할 경우, IllegalStateException 이 발생할수 있습니다.

이외에, 코루틴 공식 문서에 Dispatchers.Unconfined 도 존재합니다.

Dispatchers.Unconfined 는 다른 Dispatcher 와 는 달리 특정 스레드 또는 특정 스레드 풀을 지정하지 않습니다. 일반적으로는 사용하지 않으며 특정 목적을 위해서만 사용됩니다.

Dispatcher.Unconfined 는 이 기초 문서에서는 다루지 않습니다.

Dispatcher 에 관한 공식 문서는 이곳 에서 확인하실수 있습니다.

2. 코루틴은 이렇게 쓰면 됩니다

1. 사용할 Dispatcher 를 결정하고2. Dispatcher 를 이용해서 CoroutineScope 만들고3. CoroutineScope 의 launch 또는 async 에 수행할 코드 블록을 넘기면 됩니다.

launch 와 async 는 CoroutineScope 의 확장함수 이며, 넘겨 받은 코드 블록으로 코루틴을 만들고 실행해주는 코루틴 빌더 입니다.

launch 는 Job 객체를, async 는 Deferred 객체를 반환 하며, 이 객체를 사용해서 수행 결과를 받거나, 작업이 끝나기를 대기하거나, 취소하는 등의 제어가 가능합니다.

launch, async, Job, Deferred 의 자세한 사용법은 다음 포스트에서 알아보겠습니다.

다음은 코루틴 블록을 만들고 실행하는 가장 기본적인 코드 형태 입니다.

다음 예시는 모두 백그라운드 에서 동작 합니다

첫번째 블록처럼 CoroutineScope 를 새로 만들면 제어범위가 달라집니다.

두번째 블록처럼 launch 의 Dispatcher 를 변경하면 CoroutineScope 는 유지되면서 작업이 처리되는 스레드 만 변경됩니다.

제어범위가 다르면 다음과 같은 상황이 발생합니다.

다음 예시에서 내부 코루틴 블록은 멈추지 않습니다

기존 CoroutineScope 를 사용할지, 새로운 CoroutineScope 를 만들지 결정하는것은 코루틴 블록이 특정 상황에 어떻게 동작할 지를 결정하게 됩니다.

위 예시 에서는 외부 코루틴 블록 의 내부에서 새로운 CoroutineScope 를 만들었습니다.

이로서 외부 코루틴 블록 과 내부 코루틴 블록은 서로 제어범위가 달라집니다.

Job 객체의 cancel() 메서드는 자신이 해당하는 CoroutineScope 의 코루틴 블록을 취소시켜 멈출수 있지만, 내부 코루틴 블록은 다른 CoroutineScope 로 분리 되었기 때문에 멈출수 없습니다.

외부 코루틴 블록이 멈춰도, 내부 코루틴 블록은 끝까지 수행됩니다.

3. 코루틴 제어를 위한 주요 키워드

- launch , async
- runBlocking
- Job , Deferred

위에서 가볍게 살펴 본 바와 같이 launch, async 는 코루틴 블록을 만들며, 아직 다루지 않은 runBlocking 은 내부 작업이 종료될때까지 일시 중지 됩니다.

코루틴 블록을 제어하고 값을 전달받기 위해서는 launch 와 async 가 반환하는 Job, Deferred 객체를 사용합니다.

이 키워드 들에 대해서는 다음의 포스트에서 자세히 알아보도록 하겠습니다.

감사합니다.

참고

--

--