코루틴에서 쓰이는 개념인 suspend 함수는 과연 무엇일까 궁금해서 찾아봤다.
suspend의 사전적 의미는 '중지하다' 이다.
코루틴에서의 suspend 키워드는 시작하고, 멈추고, 다시 시작할 수 있는 함수를 뜻한다고 한다.
suspend 키워드를 붙이면 일반함수도 비동기적으로 실행할 수 있다.
일반 함수는 하나의 thread가 block될 경우, 해당 thread는 다른 작업을 할 수 없는 block 상태에 놓이게 된다. 즉 block 상태가 풀릴 때 까지 해당 thread는 중지되어 다른 작업을 못한다.
그러나 suspend function을 사용한다면 block된 상태에 놓일 때, 이 함수를 잠시 suspend 하고 그 기간동안 thread에서 다른 작업을 수행할 수 있다. 완전 효율적이다!
쉬운 비유
suspend 함수를 사용하는 경우와 하지 않을 때 Thread 자원을 어떻게 활용하는지 봐보자.
fun main(){
CoroutineScope(Dispatchers.IO).launch {
//async 이용해 병렬 수행
async { nonSuspend1() }
async { nonSuspend2() }
}
}
fun nonSuspend1(){
Thread.sleep(3000)
Log.d(TAG, "{nonSuspend1} After 3s in (${Thread.currentThread().name})")
Thread.sleep(3000)
Log.d(TAG, "{nonSuspend1} After 6s in (${Thread.currentThread().name})")
Log.d(TAG, "{nonSuspend1} END in (${Thread.currentThread().name})")
}
fun nonSuspend2(){
Thread.sleep(1000)
Log.d(TAG, "{nonSuspend2} After 1s in (${Thread.currentThread().name})")
Thread.sleep(3000)
Log.d(TAG, "{nonSuspend2} After 4s in (${Thread.currentThread().name})")
Log.d(TAG, "{nonSuspend2} END in (${Thread.currentThread().name})")
}
각 함수 nonSuspend1 과 nonSuspend2는 각기 다른 thread 실행됐음을 알 수 있다.
왜냐하면 Thread.sleep() 동안 thread가 block 되어 다른 작업은 수행될 수 없기 때문에, 각 함수는 다른 스레드에서 작동한다.
fun main(){
CoroutineScope(Dispatchers.IO).launch {
suspendTask1()
suspendTask2()
}
}
suspend fun suspendTask1() {
delay(3000)
Log.d(TAG, "[suspendTask1] After 3s in (${Thread.currentThread().name})")
delay(3000)
Log.d(TAG, "[suspendTask1] After 6s in (${Thread.currentThread().name})")
Log.d(TAG, "[suspendTask1] END in (${Thread.currentThread().name})*****")
}
suspend fun suspendTask2() {
delay(1000)
Log.d(TAG, "[suspendTask2] After 1s in (${Thread.currentThread().name})")
delay(3000)
Log.d(TAG, "[suspendTask2] After 4s in (${Thread.currentThread().name})")
Log.d(TAG, "[suspendTask2] END in (${Thread.currentThread().name}) *****")
}
Task1과 Task2가 동일한 thread에서 실행되었음을 알 수 있다.
왜냐하면 delay() 동안 thread가 suspend되어 다른 함수의 작업을 수행할 수 있기 때문이다.
(단, suspend 를 사용한다고 무조건 하나의 스레드에서만 실행되는 것은 아니다. 여기서는 2개의 함수(task1, task2) 의 작업(Log.d를 실행하는 것)이 서로 다른 시간에 일어나기 때문에 가능한 것.)
참고