[Kotlin] 코루틴 suspend 함수 질문좀 드립니다.
조회수 843회
코루틴을 공부중인데 잘 이해가지 않는 부분이 있어 질문드립니다.
1.suspend 함수는 호출된 곳의 코루틴을 정지시키나요?
suspend fun exampleSuspend() {
val job1 = CoroutineScope(Dispatchers.IO).async {
(1..1000).sortedByDescending { it }
println("job3 Coroutine")
}
val job2 = CoroutineScope(Dispatchers.Main).launch {
val job1Result = job1.await()
println("job1 Coroutine")
}
val job3 = CoroutineScope(Dispatchers.Main).async {
println("job2 Coroutine")
}
}
여기서 exampleSuspend()
함수는 3개의 코루틴을 가지고 있습니다.
그중 job2
코루틴은 job1
코루틴의 결과가 필요한 작업입니다.
그런데 여기서 job1.await()
가 실행이되면 job1 Coroutine
이 멈추는것이 아니라
이 job1.await()
를 호출한 곳의 Coroutine을 호출시키나요? 여기서는 job2 Coroutine
이 되겠네요
2.suspend함수는 블록({})에 delay라던지 await 같은 일시정지가 없어도 무조건 코루틴을 일시정지 시키나요? (or 코루틴을 정지하고 suspend 함수를 완료하나요?)
3.1번과 2번 질문의 합쳐진 질문입니다.
fun main() {
CoroutineScope(Dispatchers.IO).launch {
exampleSuspend()
println("Check..1")
}
Thread.sleep(5000)
}
suspend fun exampleSuspend() {
val job = CoroutineScope(Dispatchers.IO).async {
(1..1000).sortedByDescending { it }
println("Check..2")
}
job.await()
println("Check..3")
}
1번질문과 연동해서 만약에 await()가 호출된 지점의 Coroutine을 정지시킨다면 job.awit()
는
job Coroutine을 일시정지 시키는 것이 아니라
main함수
의 Coroutine을 존재시킬것이다 라는 것이 제 예상입니다.
exampleSuspend()
에 있는 job.await()
는 job 코루틴 블록 내부에 있는것이 아니라 main함수
의 코루틴 블록에서 호출되었으니까요.
따라서 실행 흐름은 파일이 실행되면 exampleSuspend()
가 실행되고 job 코루틴이 실행되고 또한
비동기(?)
실행으로 인해 job.await()도 실행되고 main 함수의 코루틴이 일시정지하게됩니다.
즉 println("Check..1")
은 실행하지 않고 exampleSuspend()
가 완료되기까지 정지되어있습니다.
그다음 job 코루틴일 끝나고 나머지 뒤의 코드도 실행하게 됩니다.
exampleSuspend()
의 job또한 코루틴을 가지고 있으므로 코루틴이 실행된다하더라고 이후코드는 계속 실행되므로 결과가 Check..2가 먼저 호출될지 Check..3가 먼저호출되는지는 예상을 못하겠는데
Check..2
Check..3
Check..1
순서로 실행이 되네요..우연인지 job.await
가 job 코루틴 실행까지 일시정지해서 막은건지 잘모르겠습니다.
그리고
job.await()
를 지운다면
Check..3
Check..1
Check..2
순서로 실행이됩니다. await() 시키는 것이 없어서그런지 이런식으로 결과가 나옵니다.
딱 비동기 실행(?) 그대로 나온것같죠.
그런데 이결과는 2번 질문과 연동해서 suspend 함수는 일단 무조건 정지시키는게 아니다
라고 들리는데 맞을까요? 2번 질문에서처럼 suspend 함수가 무조건 코루틴을 일시정지 시키는것이라면
exampleSuspend()가 실행되고 메인 함수의 코루틴은 멈췄어야하지 않을까요?
헷갈리네요.. 어떻게 되는건지..
1 답변
-
await()도 suspend 함수에요.말씀하신 것처럼 결과가 반환될 때까지 job2가 멈추게 됩니다.
suspend 함수가 코루틴의 핵심인데요, 결론적으로 suspend 함수를 호출한 코루틴은 suspend가 종료될 때까지 일시 정지됩니다.
참고로, suspend 함수가 호출되면 그 코루틴을 실행하던 쓰레드는 다른 코루틴을 할당받을 수 있는 상태로 바뀌고, suspend 함수는 다른 쓰레드가 할당 받아서 실행하는 구조에요. suspend가 끝나면 디스패처가 할당 가능한 쓰레드를 찾아서 정지됐던 코루틴을 재개합니다.
suspend는 항상 그것을 호출한 코루틴을 정지시키는 게 맞아요. 근데 왜 await()을 지웠을 때 check..3가 먼저 출력되냐면, async와 같은 빌더로 코루틴을 시작하면 별개의 코루틴이 시작되기 때문입니다. 즉, 부모-자식 관계는 형성이 되지만, 다른 쓰레드에 자식 코루틴을 할당합니다. 그래서 동작은 제각각이 되는거고, job이 끝나든 말든 부모 코루틴은 일단 자기 코드가 다 끝났으면 종료됩니다. 그렇다고 자식 코루틴이 종료되진 않아요. 자식과 부모가 함께 종료되는 경우는 부모 job을 cancel하는 경우입니다.
근데 여기서 job.await()을 하면 job이 끝나기 전까진 부모(여기선 exampleSuspend) 코루틴을 멈추겠다는 뜻이고, await()을 제거하면 위에서 말씀드린 것처럼 됩니다. 참고로, await을 호출하지 않으면 그냥 launch한 거랑 똑같아요. 그래서 launch를 실행 후 망각이라는 개념으로 이야기 하더라구요.
댓글 입력