테크과학! DiMo
개발 환경: play.kotlinlang.org
코루틴(coroutine)
메인이 되는 루틴과 별도로 진행이 가능한 루틴으로 개발자가 루틴의 실행과 종료를 마음대로 제어할 수 있는 단위이다.
코루틴을 사용할 때는 import kotlinx.coroutines.* 하여야 한다
코루틴의 scope
코루틴은 제어 범위 및 실행 범위를 지정할 수 있다.
- GlobalScope
프로그램 어디서나 제어, 동작이 가능한 기본 범위
- CoroutineScope
특정한 목적의 Dispatcher를 지정하여 제어 및 동작이 가능한 범위
CoroutineScope를 만들 때 적용 가능한 Dispatcher
Dispatchers.Default => 기본적인 백그라운드동작
Dispatchers.IO => I/O에 최적화 된 동작
Dispatchers.Main => 메인(UI) 스레드에서 동작
이러한 Dispatcher들은 모든 플랫폼에서 지원되지는 않음. 따라서 지원되는 플랫폼에 따라서 사용해야 한다.
코루틴은 이러한 Scope에서 제어되도록 생성될 수 있다.
val scope = CoroutineScope(Dispatcher.Default)
val coroutineA = scope.launch{}
val coroutineB = scope.async{}
launch vs async
반환 값이 있는지 여부!
launch : 반환 값이 없는 Job 객체
async : 반환 값이 있는 Deffered 객체
launch, async 모두 람다 함수의 형태를 가지고 있기 때문에 그렇기 때문에 async는 마지막 구문의 실행 결과(그림에서는
sum)가 반환된다.
import kotlinx.coroutines.*
fun main() {
val scope = GlobalScope
scope.launch {
for (i in 1..5) {
println(i)
}
}
}
Output:
실행x(라고 설명하는데, 내 인터넷 환경에서는 1 2 3 4 5(줄바꿈 없이 출력될 때도 있고, 줄바꿈 되서 출력 될 때도 있었다.)
코루틴은 제어되는 스코프 또는 프로그램 전체가 종료되면 함께 종료되기 때문에 코루틴이 끝까지 실행되는 것을 보장
하려면 일정한 범위에서 코루틴이 모두 실행될 때 까지 잠시 기다려야 한다.
우리가 테스트 하는 루틴의 경우 main() 함수 단 하나이기 때문에 프로세스가 거의 '실행 즉시 종료' 되므로 코루틴도 동작되지 못한 것.
이럴 때는 runBlocking{ }을 만들고 이 안에서 launch{}나 async{} 직접 생성하면 코루틴이 종료될 때까지 메인 루틴을 잠
시 대기 시켜준다.
주의할 점은 안드로이드에서는 메인 스레드에서 runBlocking을 걸어주면 일정 시간 이상 응답이 없는 경우
ANR(Application Not Responding)이 발생하여 앱이 강제 종료 된다.
import kotlinx.coroutines.*
fun main() {
runBlocking {
launch {
for (i in 1..5) {
println(i)
}
}
}
}
Output:
1
2
3
4
5
루틴의 대기를 위한 추가적인 함수
delay()
delay(millisecond:Long) millisecond 단위로 루틴을 잠시 대기시키는 함수
join()
Job.join() Job의 실행이 끝날 때 까지 대기하는 함수
await()
Deferred.await() Deffered의 실행이 끝날 때 까지 대기하는 함수
또한 await()는 Deferred의 결과도 반환함
세 함수들은 코루틴 내부 또는 runBlocking{}과 같은 루틴의 대기가 가능한 구문 안에서만 동작이 가능하다.
import kotlinx.coroutines.*
fun main() {
runBlocking {
val a = launch {
for (i in 1..5) {
println(i)
delay(10)
}
}
val b = async {
"async 종료"
}
println("async 대기")
println(b.await())
println("launch 대기")
a.join()
println("launch 종료")
}
}
Output:
async 대기
1
async 종료
launch 대기
2
3
4
5
launch 종료
코루틴에 cancel()을 걸어주면 다음 두 가지 조건이 발생하며 코루틴을 중단 시킬 수 있다.
1. 코루틴 내부의 delay() 함수 또는 yield() 함수가 사용된 위치까지 수행된 뒤 종료됨
2. cancel()로 인해 속성인 isActive가 false가 되므로 이를 확인하여 수동으로 종료함
import kotlinx.coroutines.*
fun main() {
runBlocking {
val a = launch {
for (i in 1..5) {
println(i)
delay(10)
}
}
val b = async {
"async 종료"
}
println("async 대기")
println(b.await())
println("launch 취소")
a.cancel()
println("launch 종료")
}
}
Output:
async 대기
1
async 종료
launch 취소
launch 종료
withTimeoutOrNull()
제한시간 내에 수행되면 결과 값을, 아닌 경우 null을 반환
이 함수도 join()이나 await()처럼 blocking 함수이다.
fun main() {
runBlocking {
var result = withTimeoutOrNull(50) {
for (i in 1..10) {
println(i)
delay(10)
}
"Finish"
}
println(result)
}
}
Output:
1
2
3
4
null
완강 소감
이 강의로 코틀린 문법을 입문한 것은 다행이라고 생각한다. 필요한 부분을 짧고 쉽게 설명해주셔서 쉽게
비교적 쉽게 완강할 수 있었다. 다만 실행 환경을 웹상에서 진행하였기 때문에 실제 IDE(인텔리제이)에서의
숙련도는 오르지 않아, 인텔리제이에서 사용이 익숙해지도록 인텔리제이에서도 코틀린 코드 작성을 해봐야
할 것 같다. 이 글을 보는 사람이 있을지 모르겠지만, 만약 코틀린 문법을 입문한다면 이 강의로 시작해 봐
도 좋을 것 같다는 생각이 든다.
이 강의의 제작자인 디모 님에게 감사의 인사 올린다.
'Kotlin > 기본 문법' 카테고리의 다른 글
코틀린(Kotlin) trimMargin() (0) | 2020.12.28 |
---|---|
코틀린 강좌 #29 비트연산 (0) | 2020.12.24 |
코틀린 강좌 #28 변수의 고급 기술. 상수, lateinit, lazy (0) | 2020.12.24 |
코틀린 강좌 #27 컬렉션 함수, 두번째 이야기! (0) | 2020.12.24 |
코틀린 강좌 #26 컬렉션 함수, 첫번째 이야기! (0) | 2020.12.24 |