runBlocking은 새로운 코루틴을 만든다.fun main(): Unit = runBlocking {
}
fun main() {
runBlocking {
printWithThread("START")
launch {
delay(2_000L) // 코루틴을 지정 시간 동안 지연시킴
printWithThread("LAUNCH END")
}
}
printWithThread("END")
}
[main] START
[main] LAUNCH END
[main] END
runBlocking 코루틴이 모두 실행될 때까지는 출력될 수 없다.runBlocking은 이처럼 스레드를 블락시키기에 프로그램에 진입하는 최초 진입 함수나 테스트 코드를 시작할 때만 쓰는 것이 좋다.runBlocking과 다르게 코루틴을 제어할 수 있는 객체 Job을 반환 받는다.
CoroutineStart.LAZY 옵션을 주면 job.start()를 호출할 때까지 실행되지 않는다.
fun main(): Unit = runBlocking {
val job = launch(start = CoroutineStart.LAZY) {
printWithThread("Hello launch")
}
delay(1_000L)
job.start()
}
cancel() 함수로 코루틴을 취소시킬 수도 있다.
fun main(): Unit = runBlocking {
val job = launch {
(1..5).forEach {
printWithThread(it)
delay(500) // 1초에 2까지 출력
}
}
delay(1_000L) // 1초 기다리고
job.cancel() // cancel 호출
}
join()으로 코루틴이 끝날 때까지 대기할 수도 있다.job1이 실행되고 delay 시작job1이 대기하는 순간 job2가 시작job1과 job2가 함께 대기job1의 대기가 먼저 끝나고 “Job1” 출력job2의 대기가 끝나거 “Job 2” 출력fun main(): Unit = runBlocking {
val job1 = launch {
delay(1_000)
printWithThread("Job 1")
}
val job2 = launch {
delay(1_000)
printWithThread("Job 2")
} }
join을 쓰면 job1이 끝날 때까지 job2를 기다리게 할 수 있다.fun main(): Unit = runBlocking {
val job1 = launch {
delay(1_000)
printWithThread("Job 1")
}
job1.join() // job1이 끝날 때까지 기다림
val job2 = launch {
delay(1_000)
printWithThread("Job 2")
} }
async는 launch와 유사하지만 실행 결과를 반환할 수 있다는 점이 launch와 다르다.fun main(): Unit = runBlocking {
val job = async {
3 + 5
}
}
async는 Defferred 객체를 반환한다.
Job의 하위 타입Job의 메서드들을 똑같이 가지며 추가로 await() 메서드를 가진다.fun main(): Unit = runBlocking {
val job = async {
3 + 5
}
}
val eight = job.await() // 변수에 8이 담긴다.
async는 여러 api를 동시에 호출하여 소요시간을 최소화할 수 있다.suspend fun인 delay를 호출하기 위해 suspend fun을 사용suspend fun apiCall1(): Int {
delay(1_000L)
return 1
}
suspend fun apiCall2(): Int {
delay(1_000L)
return 2
}
await 사용으로 두 api를 거의 동시에 호출하고 결과를 합칠 수 있다.fun main(): Unit = runBlocking {
val time = measureTimeMillis {
val job1 = async { apiCall1() }
val job2 = async { apiCall2() }
printWithThread(job1.await() + job2.await())
}
printWithThread("소요 시간 : $time ms") // 1000ms 조금 넘는 시간이 걸림
}
async는 callback을 사용하지 않고도 동기 방식으로 코드를 작성할 수 있게 해준다.
apiCall2() 메서드가 apiCall1() 메서드의 결과를 파라미터로 받아야 하는 경우callback 지옥에 빠지지 않고 코드를 작성할 수 있다.fun main(): Unit = runBlocking {
val time = measureTimeMillis {
val job1 = async { apiCall1() }
val job2 = async { apiCall2(job1.await()) }
printWithThread(job2.await())
}
printWithThread("소요 시간 : $time ms") // 2000ms 조금 넘는 시간
}
CoroutineStart.Lazy 옵션을 async와 함께 쓰면 await 함수를 호출했을 때 계산 결과를 계속 기다리게 된다.fun main(): Unit = runBlocking {
val time = measureTimeMillis {
val job1 = async(start = CoroutineStart.LAZY) { apiCall1() }
val job2 = async(start = CoroutineStart.LAZY) { apiCall2() }
printWithThread(job1.await() + job2.await())
}
printWithThread("소요 시간 : $time ms") // 2000ms 조금 넘는 시간
}
CoroutineStart.Lazy 옵션을 사용하고 싶다면 start를 미리 호출해주면 된다.fun main(): Unit = runBlocking {
val time = measureTimeMillis {
val job1 = async(start = CoroutineStart.LAZY) { apiCall1() }
val job2 = async(start = CoroutineStart.LAZY) { apiCall2() }
printWithThread(job1.await() + job2.await())
}
job1.start()
job2.start()
printWithThread("소요 시간 : $time ms") // 1000ms 조금 넘는 시간
}