본문 바로가기

ANDROID/Coroutine

[Kotlin/Coroutine] Kotlin Coroutines 101 : 코루틴을 쉽게 이해해보자!

최근에 여유가 생기면서 코틀린부터 코루틴, flow 등 공부하고 싶던 부분들에 대해 다시 들여다보기 시작했다.

 

공부를 하면서 눈에 쏙 들어왔던 건 Android Developer 채널에 올라온 아래의 영상이었다.

Kotlin Coroutines 101 - Android Conference Talks 

 

일전에 Kotlin in action에서 코루틴에 대해 살펴보기는 했지만, 이 영상을 본 뒤론 이 영상만큼 코루틴의 장점과 사용 방법 등에 대해 잘 알려주는 영상은 앞으로도 없지 않을까 싶다! (개발 영상치고 8만회의 뷰를 기록한 것이 하나의 반증이 되지 않을까?)

 

해당 영상을 기반으로 코루틴의 장점과 의의, 사용 예 등에 대해 다시 한번 정리하고자 한다.


1. 코루틴은 무엇이며, 무엇을 해결해 주는 걸까?

- 코루틴은 비동기 처리를 제공함과 동시에 높은 가독성을 제공한다. (Rx만 떠올려보아도..) 

- 코루틴은 복잡할 수 있는 비동기 처리를 보다 손쉽게 구성할 수 있도록 도와준다.

2. 코루틴의 Dispatchers들과 사용 예

- Dispatchers.Main : UI 작업 및 Non-blocking 코드에 사용

- Dispatchers.IO : IO와 관련된 Network, DB transaction을 수행할 때 사용

- Dispatchers.Default : 복잡하고 속도를 중시하는 연산을 수행할 때 사용 (Rx의 Computation Scheduler를 떠올려보자)

3. 코루틴이 내부에서 동작하는 방식

- 컴파일러는 코루틴을 Callback fuction을 가진 함수로써 생성한다.

- 고로 코루틴 function들은 기본적으로 특정 동작을 수행하고, 완료 이후 반환하는 callback에 맞물려 돌아간다 이해하면 될 듯 싶다.

4. Structured Concurrency(구조화된 동시성)

- 누가 기존의 동작을 취소할 수 있는가? 해당 동작은 앱의 lifecycle을 충분히 준수하는가? 예외가 발생하면 이를 누가 처리하는가?

- 위와 같은 물음을 해소하기 위해 코루틴은 구조화된 동시성 을 내세운다.

- 이 개념을 베이스로 만들어진 scope, launch나 async 블록을 사용하면 개발자는 메모리 누수 및 동시성을 가진 function들을 올바르게 처리할 수 있게 된다!

5. 코루틴의 예외처리 하기

- 코루틴의 scope 내부에서 예외가 발생하는 경우 이를 try catch 블록에서 감싸도록 한다. 

- scope을 별도 변수에다 할당하고, 예외가 발생하는 경우 해당 scope을 cancel 시키는 동작이 가능하다.

- scope내에서 특정 suspend function에 오류가 발생하더라도 멈추지 않고, 이후 수행하는 특정 Job까지 수행한다.

6. 언제 launch를, 언제 async를 써야 할 까?

- 단발성 작업, 별도의 value 값을 받는 동작이 아니라면 launch를, value 값을 받아야 하는 경우 async를 사용하자!

- Async의 경우 별도의 await call이 있기 전까지 발생한 exception을 hold하고 있다는 점도 재밌는 부분인듯.

 

suspend fun getUser(userId: String): User {
	coroutineScope {
    		val deffered = async(Dispatchers.IO) {
        		userService.getUser(userId)
        	}
        
        	// deffered async 블록이 콜백을 받고 작업을 마치기 이전까지 coroutineScope을 종료하지 않으며
        	// 작업을 마치고 콜백으로 데이터를 return하는 경우 scope을 종료하고 getUser로 User 데이터를
                // 넘겨주게 된다!
        	deffered.await()   
    }    
}

이것은 너무너무나도 잘 정리된 Launch와 Async의 공통점과 차이

7. 어떤 메소드를 suspend로 사용하고, 또 사용하지 말아야 할 까?

- 위 영상의 Instructor인 Manuel Vivo는 간단하게 이를 정리하는데, 내용은 아래와 같다.

- suspend로 불러야 하는 function이 있는 경우 suspend를 사용하면 된다(..!)

- suspend로 반드시 불러야 하는 경우가 아니라면 suspend를 사용하지 말아라.

- .. 그럼 어느 기능을 최초로 suspend로 불러야 하는가? : I/O 동작 및 동시성을 보장해야 할 function으로!

8. 코루틴의 유닛 테스팅

- 코루틴의 suspend function들은 runBlocking 코드블럭으로 수행하면 된다.

- 다만 동적으로 scope을 만드는 경우에는 Dispatchers를 파라미터로 넘겨받는 ViewModel을 사용해야 한다!

 

< 참고 > 

Kotlin Coroutines 101 - Android Conference Talks  

by Imanuel Vivo in Google