본 포스팅은 DroidKaigi 2019 ~ Understanding Kotlin Coroutines: コルーチンで進化するアプリケーション開発 을 기본으로 번역하여 작성했습니다
제 일본어 실력으로 인하여 오역이나 오타가 발생할 수 있습니다.
일부 이미지는 이해를 돕고자 한국어로 수정했습니다.
번역에서 사용한 이미지는 원본은 https://speakerdeck.com/mhidaka/understanding-kotlin-coroutines-korutindejin-hua-suruapurikesiyonkai-fa 에 있습니다.
Coroutine으로 진화하는 앱 개발
@mhidaka
발표시에 오류가 있는 곳을 다음과 같이 수정했습니다.
DroidKaigi / TechBooster / 기술서전
Main points
The first step is always the hardest
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // Coroutine 시작
delay(1000L) // Coroutine을 1초 중단
println("World!") // "World" 출력
}
println("Hello,") // 메인 스레드에서 "Hello," 출력
Thread.sleep(2000L) // 스레드를 2초 정지(JVM이 종료되지 않도록)
}
$ > Hello, World!
https://kotlinlang.org/docs/reference/coroutines/basics.html
CC BY SA 2.0 https://www.flickr.com/photos/librariesrock/44436145281/
일괄 처리에 대해 중단과 재시작을 제공
source : Understanding Kotlin Coroutines: コルーチンで進化するアプリケーション開発
Job A~C에 대해 처리 중단/재시작을 제공한다 (스레드를 블록하지 않는다!)
GlobalScope.launch { // Coroutine 시작
delay(1000L) // Coroutine을 1초 중단
println("World!") // "World" 출력
}
suspend fun delay(timeMillis: Long): Unit (source)
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/delay.html
복수 코루틴이 협조하고 자원을 유효하게 활용
Coroutine1 함수가 분할해서 실행하는 부분에 주의
앞의 상태를 이어받는 것.
컴퓨터 사이언스에서는 프로그램의 실행 중에 아직 평가되지 않은 남은 프로그램이나 처리를 완료하기 위한 처리나 구조를 가리킨다.
2019/2/11, 슬라이드에 잘못된 지식으로 오류가 있었으므로 정정합니다. 연속의 이해에는 다음 자료를 추천합니다. http://practical-scheme.net/docs/cont-j.html
스레드도 연속의 구현 형태의 하나. 서브 루틴에는 코루틴같은 중단은 없으므로 반드시 끝나지 않으면 다음 함수는 호출되지 않습니다. 멀티 스레드 프로그래밍에 따른 협조 동작과 동시성을 확보하고 있습니다.
callbackA ( a -> {
callbackB ( b -> {
callbackC ( c -> {
sum = a + b + c
})
})
})
launch { // 코루틴 시작
val a = callbackA()
val b = callbackB()
val c = callbackC()
val sum = a + b + c
}
Cancellation
https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html
GlobalScope.launch { // Coroutine 시작
delay(1000L) // Coroutine을 1초 중단 → Job A
println("World!") // "World" 출력 → Job B
}
object GlobalScope : CoroutineScope { ... }
앱 개발에 있어서는 일반적으로 GrobalScope는 사용하지 않습니다. 앱 내의 생명주기에 따라 CoroutineScope를 자체 정의하는 것을 적극적으로 추천합니다.
val job = CoroutineScope(Dispatchers.Default).launch{
repeat(1000) { i ->
println(“I‘m sleeping $i ...”)
delay(500L)
}
}
delay(1300L) // 1.3초 중단
println("main: I’m tired of waiting!")
job.cancel() // Job 중지
job.join() // 중지 처리 종료 대기
println("main: Now I can quit.")
https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html
CC BY-SA 2.0 https://www.flickr.com/photos/bobellaphotography/8494268626/
동시성 : 프로그램이나 문제 해결에서 순서에 의존하지 않고, 부분적인 컴포넌트로 나눠서 리소스를 최대한 활용 (문제를 해결) 하는 구성
병렬성 : 동시에 복수 처리를 실행 (Execution) 하는 것
이 그림은 프로그래밍에서 말하는 Sequence 처리입니다.
이 그림은 동시성일까요? 병렬성일까요?
실은 두 가지 모두 가지고 있습니다. 책을 책장으로 옮긴다는 의미에서는 병렬로 실행이 가능합니다. 옮기는 사람이 넘어져도, 다른 한쪽은 실행 가능한 병렬성입니다. 실제로 2배의 속도로 처리되는 것처럼 보이므로 동시성이기도 합니다.
위 부분에 2명을 더 투입해서 시간을 나눠서 진행해 더 효율적으로 처리하는 부분에서는 동시성입니다.
이 그림에서는 책장은 병렬성이 있습니다. 그러나, 책을 옮기는 부분에는 복수의 인원이 작업하므로 동시성을 가집니다.
보다 효율적으로 작업한다면 책장에 책을 넣는 사람을 투입해서 병렬성을 확보할 수 있습니다.
책을 넣는 사람이 한 명이 쓰러져도 남은 한 명으로 처리를 이어나갈 수 있습니다.
복수 코루틴의 동시처리 / 제어를 도와주는 구성
버전 0.26.0에서 CoroutineScope를 도입
suspend fun loadFromNetwork(endPoint1: String, endPoint2: String): ResultData {
val result1 = callApi(endPoint1)
val result2 = callApi(endPoint2, result1) // 최초 결과를 사용
return combineResults(result1, result2) // 결과를 합쳐서 반환
}
suspend fun callApi(endPoint: String): ResultData { ... } // 네트워크 처리
suspend fun loadFromNetwork(endPoint1: String, endPoint2: String): ResultData {
val result1 = async { callApi(endPoint1) }
val result2 = async { callApi(endPoint2, result1) }
return combineResults(result1.await(), result2.await())
}
fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T> (source)
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
suspend fun loadFromNetwork(endPoint1: String, endPoint2: String): ResultData = coroutineScope {
val deferred1 = async { callApi(endPoint1) }
val deferred2 = async { callApi(endPoint2) }
combineResults(deferred1.await(), deferred2.await())
}
interface Deferred<out T> : Job (source)
abstract suspend fun await(): T
https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html
! | 코루틴은 기본 위에서 아래로 순차처리입니다. 동시 처리하고 싶은 경우에 async/await로 기다리게 한다. 이것은 동시 처리의 개념이 어렵고 join을 잘못썼을 때에는 복잡한 문제가 발생하기 위한 조치이다. 여담 : C#은 동시 처리가 기본이므로 “Classic way”라고 부른다 |
Introduction of application problem to be solved
직면하는 과제
CC BY-SA 2.0 https://www.flickr.com/photos/ooocha/2849172733/
좋은 UX를 제공하기 위해서는 통신, 처리 시간이 걸리는 것을 백그라운드 태스크로 해서 UI 스레드를 블록킹하지 않는 구조를 요구한다
관심 분리 (Separation of concerns) 단일 책무 원칙 (Single Responsibility Principle)
이것에 근거해 설계된 모듈이 유기적으로 연계한다
기대되는 코루틴 역할
중단/재시작에 따른 리소스 보호
CoroutineScope에 의한 명확한 구조화
고효율 동시성을 획득
모듈간의 시퀀스를 생각한다
앱에 적용
MVVM 아키텍쳐에서 실천하는 코루틴
fab.setOnClickListener { view ->
plantDeailViewModel.addPlantToGarden()
Snackbar.make(view, R.string.add_plant_to_garden, Snackbar.LENGTH_LONG).show()
}
suspend fun createGardenPlanting(plantId: String) {
withContext(IO) {
val gardenPlanting = GardenPlanting(plantId)
gardenPlanting.insertGardenPlanting(gardenPlanting)
}
}
Coroutines의 편리한 사용법
> https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.coroutines/suspend-coroutine.html
https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive/kotlinx-coroutines-rx2
다른 아키텍쳐에서의 사용지표
모듈간의 시퀀스를 봅시다
데이터 흐름의 문제로서 아키텍처를 구성한다면 스트림으로 파악하고 RxJava 등을 사용해 해결
모듈 단위로 관심을 분리하고 독립성이 높은 개발 모델을 주관으로 하는 경우에는 관심을 모듈이라는 단위로 분리한다
동시성을 도입하고 책무를 단일로 분해하기 위한 제약을 구한다
생명주기에 밀접하게 관련된 책임의 분리
Android specified한 기능을 추상화하고 인터페이스를 제공
정리 : Android 앱에 있어서 Corutines의 역할
코루틴은 동시성을 고품질로 다루기 위한 구성 가볍고 중단 가능, Android 앱 개발의 향후 표준
코루틴을 알고, 혼자라도 코드 속을 이해할 수 있는 기초와 앱에의 응용을 Kotlin Coroutines이 복잡한 비동기 처리 과제를 해결하고, 누구도 이해할 수 있는 클린 코드의 초석이 될 거라고 기대합니다
예외의 전파나 코루틴 간의 통신을 하는 Channel, Select 등은 다루지 않았습니다. Channel 등은 Experimental 구현으로 존재합니다. 코루틴의 연계를 실현하는 기능
Session keyword: continuation, concurrency, cancellation, launch, suspend, coroutine scope, async, await, job, coroutine context, withContext, suspendCoroutine
코루틴을 사용해 앱 개발을 더 재미있도록!
Enjoy Coroutines More fun app development
Thank You! rabbitlog@gmail.com
https://kotlinlang.org/docs/reference/coroutines/basics.html 공식 레퍼런스의 기초편
https://www.youtube.com/watch?v=P7ov_r1JZ1g KotlinConf 2018 - Android Suspenders by Chris Banes
comments powered by Disqus
Subscribe to this blog via RSS.
LazyColumn/Row에서 동일한 Key를 사용하면 크래시가 발생하는 이유
Posted on 30 Nov 2024