Coroutine 사용하기
- import kotlinx.coroutines.*
Coroutine의 특징
- 제어 범위 및 실행 범위를 지정 할 수 있다. (Scope라 한다)
- GlobalScope, CoroutineScope를 지원
GlobalScope란?
프로그램 어디서나 제어, 동작이 가능한 기본 범위
CoroutineScope란?
특정한 목적의 Dispatcher를 지정하여 제어 및 동작이 가능한 범위
CoroutineScope 를 만들 때 적용가능한 Dispatcher은?
- Dispatcher.Default : 기본적인 백그라운드동작
- 상세 : CPU 사용량이 많은 작업에 사용합니다. 주 스레드에서 작업하기에는 너무 긴 작업 들에게 알맞습니다.
- 스레드 개수 : Dispatchers.DEFAULT는 forkJoinPool을 내부에서 쓰고 기본 개수는 cpu 코어 개수
- Dispatcher.IO : I/O에 최적화 된 동작
- 상세 : 네트워크, 디스크 사용 할때 사용합니다. 파일 읽고, 쓰고, 소켓을 읽고, 쓰고 작업을 멈추는것에 최적화되어 있습니다.
- 스레드 개수 : Dispatchers.IO는 system property(kotlinx.coroutines.io.parallelism)를 보고 없으면 64개 입니다
- Dispatcher.Main : 메인(UI) 스레드에서 동작
- 스레드 개수 : 1개인가?
- Coroutine 은 Scope에서 제어되도록 생성될 수 있다.
val scope = CoroutineScope(Dispatchers.Default) // 생성된 Scope
val coroutineA = scope.launch{} // launch 함수를 통한 새로운 Coroutine을 생성할 수 있다.
val coroutineB = scope.async{} // async 함수를 통한 새로운 Coroutine을 생성할 수 있다.
launch
반환값이 없는 job 객체
async
반환값이 있는 Deffered 객체
CODE
// 테스트 (1)
import kotlinx.coroutines.*
class CoroutineMain
fun main() {
val scope = GlobalScope
scope.launch {
for (i in 1..5){
println(i)
}
}
}
/*
(출력)
Process finished with exit code 0
*/
실행 결과 아무 값도 출력 되지 않는다.
이유는?
코루틴은 제어되는 스코프 또는 프로그램 전체가 종료되면 같이 종료 된다.
코루틴이 실행되는 것을 보장하려면 코루틴을 기다려 주어야 한다.
// 해결 방법
runBlocking {
launch{}
async{}
{
runBlocking 을 사용하면 main 루틴을 잠시 대기 시켜준다.
안드로이드에서는 main thread에서 runBlocking을 걸어주고 일정 시간에 응답이 없는경우 (ARN)이 발생함으로 주의한다.
// 테스트 (1)
import kotlinx.coroutines.*
class CoroutineMain
fun main() {
val scope = GlobalScope
runBlocking
scope.launch {
for (i in 1..5){
println(i)
}
}
}
}
/*
(출력)
1
2
3
4
5
*/
그럼 루틴의 대기 처리는 어떻게 할 수 있을까
delay() : delay(milisecond:Long)
milisecond 단위로 루틴을 잠시 대기
join() : job.join()
Job의 실행이 끝날때까지 대기하는 함수
awit() : Deferred.await()
Deferred의 실행이 끝날때까지 대기하는 함수
위 함수는 루틴의 대기가 가능한 공간 안에서만 동작이 가능하다
CODE
fun main() {
val scope = GlobalScope
runBlocking {
val a = scope.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 종료")
}
}
/*
(출력)
1
async 대기
async 종료
launch 대기
2
3
4
5
launch 종료
*/
그럼 루틴의 실행 중단 방법은?
cancle() : 함수를 통해 중단 가능
코루틴 내부의 delay() 함수 또는 yield() 함수가 사용된 위치까지 수행된 뒤 종료함
cancle()로 인해 속성인 isActive가 false 되므로 이를 확인하여 수동으로 종료함
CODE
fun main() {
val scope = GlobalScope
runBlocking {
val a = scope.launch {
for (i in 1..5){
println(i)
delay(10)
}
}
val b = async {
"async 종료"
}
println("async 대기")
println(b.await())
println("launch 대기")
a.cancel() //cancel로 변경
println("launch 종료")
}
}
/*
1
async 대기
async 종료
launch 취소
launch 종료
*/
withTimeoutOrNull() : 제한 시간내 수행하면 결과값을 아닌경우 null을 반환하는 함수
fun main() {
val scope = GlobalScope
runBlocking {
var result = withTimeoutOrNull(50){
for(i in 1..10){
println(i)
delay(10)
}
"Finish"
}
println(result)
}
}
/*
1
2
3
4
null
*/
시간내 수행되지 못해 null이 발생하는 것을 확인 할 수 있습니다.
이상으로 Coroutine을 간단히 알아보았습니다.
링크
디모의 가장쉬운 kotlin : https://www.youtube.com/watch?v=Lpieg1zrKdg&list=PLQdnHjXZyYadiw5aV3p6DwUdXV2bZuhlN&index=31