var result = 0
for (i in 1..10) {
result += i
}
println(result)
이와 같은 일반적인 구문들은 동기적(순차적)으로 처리됨을 알 수 있다.
그렇다면 코틀린에서는 비동기처리가 불가능한가? 아니다. 그래서 우리는 코루틴을 배워야 한다.
: 메인인 메인루틴과 별도로 진행이 가능한 코루틴으로 개발자가 루틴에 실행과 종료를 마음대로 제어할 수 있는 단위
import kotlinx.coroutines.*
코루틴을 사용하기 위한 패키지 import 구문이다.
: 코루틴은 제어범위 및 실행범위를 지정 가능하다.
: 스코프는 GlobalScope와 CoroutineScope 2가지가 있다.
:프로그램 어디서나 제어, 동작이 가능한 기본 단위
: 특정한 목적의 Dispatcher를 지정하여 제어 및 동작이 가능한 범위
** Dispatcher는 모든 플랫폼에서 지원이 아니기에 지원되는 플랫폼에 따라 사용
val scope = CoroutineScope(Dispatcher.Default)
val coroutineA = scope.launch {}
val coroutineB = scope.async {}
이거와 같이 코루틴 생성에는 launch와 async 함수가 있다.
그리고 이 둘의 차이는 반환값 여부이다.
launch {
for (i in 1..10) {
println(i)
}
}
async {
var sum = 0
for (i in 1..10) {
sum++
}
sum
}
이렇듯 반환이 있느냐 없느냐에서 둘을 다르게 사용해야 한다.

하지만 직접 GlobalScope 타입으로 launch함수를 통해 출력하게끔 했는데, 이상하게도 출력이 되지 않는다.
=> 코루틴은 제어되는 스코프 또는 프로그램 전체가 종료되면 같이 종료가 된다. 코루틴이 끝까지 실행되는 것을 보장하려면 일정한 범위에서 코루틴이 모두 실행될 때까지 잠시 기다려줘야 한다.
그래서 방금과 같이 루틴의 경우에서는 main 단 하나이기 때문에 프로세스가 거의 실행 즉시 종료되므로 코루틴도 동작되지 못한 것이다.
runBlocking {
launch {}
// 또는
async {}
}
이런 식으로 runBlocking을 만들고, 그 안에 launch 또는 async을 만들면 코루틴이 종료할 때까지 메인 루틴을 잠시 대기시켜 준다.

어쨌든 이렇게 runBlocking으로 코루틴이 끝날때까지 기다려줌으로써 실행이 된다.
: milisecond 단위로 루틴을 잠시 대기시키는 함수
: Job.join()으로 Job의 실행이 끝날때까지 대기하는 함수
: Deffered.await()으로 Deffered의 실행이 끝날때까지 대기하는 함수
: Deffered객체의 결과도 반환
=> 이 3개는 코루틴 내부 또는 runBlocking과 같은 루틴의 대기가 가능한 구문 안에서만 동작이 가능

이런 순으로 진행되는 것이다.
cancel() : 코루틴에 cancel()을 걸어주면 2가지 조건이 발생하며 코루틴을 중단 가능

이와같이 원래는 join으로 반복 출력이 끝날때까지 기다렸다면 지금은 cancel로 수동으로 종료했기에 2부터 출력없이 바로 종료됨을 알 수 있다.
withTimeoutOrNull() : 제한시간 내에 수행되면 결과값을, 아닌 경우 null을 반환
withTimeoutOrNull (50) {
for (i in 1..1000) {
println(i)
delay(10)
}
"Finish"
}
이런 형태로 제한시간 50ms을 준 상태에서 1부터 1000까지 10ms뒤에 다 출력하게 된다면 "Finish"를 아니라면 null을 반환하도록 하는 것이다.
이 함수도 join, await처럼 blocking 함수이다.

따라서 이와 같이 runBlocking안에 실행을 해야하며 50ms 동안 1부터 5까지의 출력을 10ms 후에 시작하도록 한다. 그렇다면 출력문에 의해 1 2 3 까지는 출력하다가 50ms가 다 지나게 되어 결국 "Finish"가 아니라 null로 반환하게 된다.