티스토리 뷰
루틴의 종류
우선 루틴의 종류에 대해 살펴보면 메인루틴, 서브루틴, 코루틴이 있다.
- 메인루틴: main 함수에 의해서 수행되는 프로그램의 흐름
- 서브루틴: main 함수 안에서 실행되는 개별함수들에 의해서 수행되는 흐름
즉 함수는 루틴의 한 종류이다!
-> 보통 루틴은 일직선적인 흐름을 가지고 있다.
코루틴
- 특징은 일직선적인 흐름을 중간에 suspend해서 지연을 시켰다가 resume을 통해 다시 재시작하는 것이 가능하다는 점이다.
- 코루틴을 사용하면 이미 실행이 되었더라도 다른 루틴이 실행되는 동안 잠시 suspend를 시켰다가 바쁜게 끝나고 나면 다시 멈춘 곳에서부터 다시 재시작해서 나머지 작업을 끝내는 비동기 프로그래밍이 가능하게 된다.
- 코루틴은 스레드가 아니다.
코루틴 구조
Coroutine Scope
- 코루틴이 어떤 범위에서 동작하는지 규정하는 코루틴 스코프가 정해지면
Coroutine Context
- 그 안에서는 어떤 스레드에서 이 코루틴을 돌릴지 결정하는 코루틴 컨텍스트를 정해준다. 코루틴 컨텍스트가 정해지면
Coroutine Builder
- 이 작업을 수행을 하고 값을 리턴을 할지 안할지 그런 부분을 정해주는 코루틴 빌더를 실행하게 된다. 그러면 코루틴 객체가 생기면서 코루틴 작업을 수행할 수 있게 된다.
코루틴 스코프
GlobalScope
- 앱의 라이프사이클과 함께 동작해서 별도의 생명주기 관리 필요하지 않다.
- Ex) 앱의 시작부터 종료까지 혹은 장시간 실행되어야 할 때 사용
CoroutineScpoe
- 작업이 필요할 때만 실행하고 완료되면 종료
- Ex) 버튼을 클릭해서 서버의 정보를 가져오거나 파일을 여는 용도
Dispatchers: 코루틴이 실행되는 스레드 지정
- Default(CPU연산을 많이 사용하는 작업에서 사용됨)
- IO(파일 IO나 네트워크 IO를 많이 사용하는 작업에서 사용됨)
- Main(UI 스레드 Main 스레드에서 UI 관련 변경을 해야 될때 사용됨)
- Unconfined(일반적인 용도로는 사용하지 않음)
코루틴 시작
launch
- 호출 시 코루틴 생성되고 Job 객체 반환, 이 Job을 변수에 저장해두고 상태 관리용으로 사용 가능
async
- 코루틴 시작하며 Deffered 객체 반환를 반환하므로 코루틴 스코프의 연산 결과를 받아 사용 가능
둘의 차이!
launch는 코루틴 작업시 시작되면 그 안에서 작업을 하고 끝이고
async에서 작업을 하면 작업을 하고 맨 마지막에 남은 숫자를 값을 반환
+ withContext: Dispatcher를 전환시키는 기능을 가짐
Job & Deferred
코틀린에서는 코루틴 작업을 Job 혹은 Deferred라는 object로 만들어서 다루게 된다.
Deferred는 결과값을 가지는 Job으로 사실상 Job으로 생각하면 된다.
코루틴이라는 어떤 그 추상적인 흐름을 Job이라고 하는 어떤 object으로 만들어서 사용한다.
코틀린에서는 이렇게 코루틴 한덩어리를 Job이라는 object로 만들게 되면
이 object에서 취소나 예외 처리를 하면 코루틴 흐름 제어 용이하게 할 수 있다.
코루틴 스코프에 대해서 launch 명령어로 코루틴 작업을 만들면 그 작업이 Job이라는 객체를 반환하게 된다.
코루틴은 일시정지 시킬 수 있는 작업의 흐름이기 때문에
Job은 코루틴의 여러 가지 상태를 반영할 수 있도록 여러 가지 상태를 가질 수 있도록 설계가 되어 있다.
Job 관련 메소드들
start
- 새로 만들어진 객체를 시작을 하게되고 ???
cancel
- 코루틴 동작을 멈춘다.
join
- 코루틴의 실행이 완료된 후에 다음 코루틴이 순차적으로 실행되도록 해준다.
Ex) 코루틴스코프 안에 여러개의 launch 블럭들이 있으면 모두 새로운 코루틴으로 분기가 되어 동시에 처리되므로 순서를 정할 수 없다. 이를 순차적으로 실행하기 위해 join 사용
CoroutineScope(Dispatchers.Default).launch() {
launch {
for(i in 0..5) {
delay(500)
Log.d("코루틴", "결과1 = $i")
}
}.join()
launch {
for(i in 0..5) {
delay(500)
Log.d("코루틴", "결과2 = $i")
}
}
+ delay: delay에 정해진 시간동안 코루틴 처리가 중단된다.
async로 실행한 코루틴에 대해서는 await 명령어를 사용해서 Job 실행이 끝날때까지 대기를시킬수가있음
특히 await를 사용하면 Deffered의 실행이 끝날때까지 대기를 시키고 이 Deffered 값을 await를 통해서 반환을 하게 된다.
CoroutineScope(Dispatchers.Default).async {
val deffered1 = async {
delay(500)
350
}
val deffered2 = async {
delay(1000)
200
}
Log.d("코루틴", "연산 결과 = ${deffered1.await() + deffered2.await()}")
}
suspend
코루틴 안에서 suspend 키워드로 선언된 함수가 호출되면 이전까지의 코드 실행이 멈추게 되고, suspend 함수의 처리가 완료된 후에 멈춰 있던 원래 스코프의 다음 코드가 실행된다.
suspend fun subRoutine() {
for(i in 0..10) {
Log.d("subRoutine", "$i")
}
}
CoroutineScope(Dispatchers.Main).launch {
// (코드 1)
subRoutine()
// (코드 2)
}
-> subRoutine은 suspend 키워드를 붙임으로 코루틴스코프안에서 자동으로 백그라운드 스레드처럼 동작
subRoutine()이 실행되면서 호출한 측의 코드를 잠시 멈췄지만 스레드의 중단은 없음!(코루틴의 특징)
runBlocking
runBlocking{} 블록은 주어진 블록이 완료될때까지
현재 스레드를 멈추는 새로운 코루틴을 생성하여 실행하는 코루틴 빌더
코루틴 빌더인 runBlocking 을 사용하면 내부 코루틴이 완료될 때까지 메인 스레드가 blocking되어 프로그램이 중단되지 않는다.
import kotlinx.coroutines.*
fun main(){
//GlobalScope.launch{} 주어진 코드블록을 수행하는 코틀린을 생성하는 코루틴 빌더
//해당 코드블록은 코루틴 안에서 수행된다.
GlobalScope.launch{
println("World!")
}
println("Hello.")
//
runBlocking{
// GlobalScope.launch{}로 실행된 코루틴의 수행이 완료될때까지
// 현재 스레드(main 함수)를 대기시키기 위해서 임의의 지연을 준다
delay(2000L)
}
// 그런데 내부적으로 실행중인 코루틴이 작업을 완료하고 종료될때까지
// 얼마나 대기해야 할지 부모 코루틴은 예측할 수 없으므로
// launch로 실행한 코루틴에 대해서는 join으로 Job의 실행이 끝날때까지
// 대기시킬수있음
}
->
fun main(args: Array<String>) = runBlocking {
val job = GlobalScope.launch {
delay(1000L)
println("World!")
}
println("Hello,")
job.join()
}
launch{} 코루틴 빌더를 이용하여 새로운 코루틴을 생성하면 현재 위치한 부모 코루틴에 join()을 명시적으로 호출할 필요없이 자식 코루틴들을 실행하고 종료될때까지 대기할 수 있다.
fun main(args: Array<String>) = runBlocking {
launch {
delay(1000L)
println("World!")
}
println("Hello,")
}
예외처리
CoroutineExceptionHandler를 이용하여 코루틴 내부의 기본 catch block으로 사용할 수 있다.
참고
https://flow9.net/bbs/board.php?bo_table=kotlin&wr_id=51
'안드로이드[Kotlin]' 카테고리의 다른 글
[Database] Room이란? (1) | 2022.02.16 |
---|---|
[안드로이드/Kotlin] 목록 화면을 만들기 위한 RecyclerView (0) | 2022.02.07 |
[아키텍처 패턴] MVP 패턴이란? (0) | 2022.02.02 |
[안드로이드/Kotlin] 뷰 바인딩이란? (1) | 2022.01.22 |
[아키텍처 패턴] MVC 패턴이란? (0) | 2022.01.12 |