1) 코루틴(Coroutine)이란 무엇인가?
코루틴은 루틴 중의 하나로 협동 루틴이라고 할 수 있다. 이름의 코(Co)는 with 또는 togather을 의미한다. 코루틴은 서로가 서로를 호출하는 관계이다. 즉, A라는 코루틴과 b라는 코루틴이 있을 때 A를 사용하면 B가 서브루틴이 되고 B가 사용되면 A가 서브루틴이 된다. 코루틴이 다시 사용될 때는 자신이 마지막으로 멈췄던 지점에서 다시 재개된다. 코루틴의 장점 중에 하나는 비동기적으로 실행된다는 점이다.
- 동기적(Synchronous) : 어떠한 작업을 요청했을 때 그 작업을 끝내고 다음 작업을 실행함
- 비동기적(Asynchronous) : 어떠한 작업을 요청했을 때 그 작업이 끝날 때 까지 기다리지 않고 다른 작업을 하다가 요청했던 작업이 끝나면 중단됐던 작업을 다시 수행함
1-1) 코루틴 설정
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0-native-mt'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.0-native-mt'
Coroutine을 입력했을 때 위처럼 뜬다면 코루틴을 사용할 준비가 된 것이다.
2) 코루틴 스코프 ( CoroutineScope)
- 글로벌 스코프(GlobalScope): 앱의 생명주기와 함께 동작하므로 생명주기를 따로 관리해 줄 필요가 없다. 앱이 시작할 때 부터 끝날 때 까지 긴 시간 실행되는 코루틴의 적합하다.
- 코루틴 스코프(CoroutineScope): 서버에서 이미지를 가져오는 경우 같은 코루틴이 필요할 때만 사용하고 닫아주는 경우에 적합하다.
3) 코루틴 디스패쳐 ( Dispatcher )
디스패처는 코루틴을 적당한 스레드에 할당하고 코루틴이 정지하거나 다시 실행하는 것을 담당한다.
코루틴 디스패처의 종류에는 Default, IO, Main, Unconfined 등이 있다.
- Dispatchers.Default : 안드로이드 기본 스레드 풀을 사용한다. CPU를 많이 쓰는 데이터 정렬이나 복잡한 연산 같은 작업에 최적화 되어있다.
- Dispatchers.IO : 이미지 다운로드, 파일 입출력 등 네트워크, 디스크, DB작업에 최적화 되어있다.
- Dispatchers.Main : 안드로이드 기본 스레드에서 코루틴을 실행한다. UI와 상호작용에 최적화 되어있다.
- Dispatchers.Unconfined : 호출한 context 를 기본으로 사용하는데 중단하고 다시 실행될 때 context가 바뀌면 바뀐 context로 따라간다.
4) 코루틴 상태관리
- cancel : 코루틴의 동작을 멈추게 하는 method이다. 하나의 스포크 안에 여러개의 코루틴이 존재할 때 하위 코루틴까지 모두 멈춘다.
- join : 코루틴 내부에 여러 launch 블록이 있을 경우 모두 새로운 코루틴으로 분기되어 동시에 실행되기 때문에 순서를 정할 수 없다. 순서를 정해야할때 join method 를 이용해서 코루틴이 순차적으로 실행할 수 있도록 할 수 있다.
5) 코루틴 suspend 함수
suspend가 붙은 함수가 호출되면 호출한 코드를 잠시 멈추게 해서 스레드가 멈추지 않는 효율적인 스레드 활용을 할 수 있게 된다. 코루틴이 멈출 때 코틀린 런타임은 해당 코루틴이 실행되던 스레드에 다른 코루틴을 할당해서 실행시킨다. 그리고 멈춰있던 코루틴이 다시 실행될 때 사용 가능한 스레드에 할당해준다. 코루틴은 멈추면서 해당 루틴 상태를 저장하고 서브 루틴을 실행한 다음 저장한 부모루틴을 복원하는 방법으로 스레드에 영향을 주지 않는다.
6) 코루틴 withContext
suspend 함수를 코루틴 스코프에서 사용할 때 호출한 스코프와 다른 디스패쳐를 사용할 경우가 있다. 이때 호출한 코루틴은 Main 디스패쳐, suspend함수는 IO 디스패쳐를 사용하는 경우 withContext를 사용해서 suspend 함수의 디스패쳐를 IO로 변경해 줄 수 있다.
CoroutineScope(Dispatchers.Main).launch{
val result = withContext(Dispatchers.IO){
run()
}
}
7) 코루틴 빌더
- launch : 현재 스레드를 중단하지 않고 코루틴을 바로 시작한다. 결과를 호출한 쪽에 반환하지 않는다. 일반 함수에서 suspend 함수를 호출할 때와 코루틴의 결과가 필요 없을 때 사용한다.
- async : 현재 스레드 중단 없이 코루틴을 바로 시작한다. launch와 다른점은 호출 쪽에서 await() 을 통해 코루틴 결과를 기다릴 수 있다. 다수의 코루틴을 사용할 때 사용한다. suspend 함수 내부에서만 사용할 수 있다.
- withContext : 부모 코루틴에 의해 사용되던 context와 다른 context에서 코루틴을 실행 할 수 있다.
- coroutineScope : 다수의 코루틴을 suspend 함수가 시작하고 모든 코루틴이 완료될 때만 어떤 처리가 필요한 경우에 적합하다. 여러 코루틴 중에서 하나라도 실패하면 모든 코루틴이 취소된다.
- supervisorScope : coroutineScope와 비슷하지만 여러 코루틴 중에서 하나가 실패해도 다르 코루틴이 취소되지 않는 다는 점이 다르다.
- runBlocking : 코루틴을 시작하고 완료될 때 까지 현재 스레드를 중단시킨다.
7-1) 코루틴 suspend function
- withTimeout : 코루틴이 정해진 시간 안에 실행되지 않으면 예외를 발생시킨다.
- withTimeoutOrNull : 정해진 시간 안에 실행되지 않으면 null을 반환한다.
- awaitAll : 모든 작업의 성공을 기다리면서 작업중에 하나라도 실패하면 awaitAll 또한 실패한다.
- joinAll : 모든 작업이 끝날 때 까지 현재 작업을 일시 중단시킨다.
참고차료:
https://developer.android.com/kotlin/coroutines?hl=ko
https://whyprogrammer.tistory.com/596
https://kotlinworld.com/139?category=973476
https://ko.wikipedia.org/w/index.php?title=%EC%BD%94%EB%A3%A8%ED%8B%B4&action=edit§ion=1