suspend fun doOne() {
launch {
println("3!")
}
}
fun main() = runBlocking {
doOne()
}
X 이 코드는 컴파일에 실패합니다.
Unresolved reference: launch
코르틴 빌더(launch)는 반드시 코르틴 내에서 호출을 해야함
- suspend 키워드가 붙어진 함수는 suspension function(함수)일 뿐이지 코루틴은 아님
- suspension function내에서 다른 suspension function인 delay는 호출이 가능함
코르틴 빌더(launch, runBlocking) 안에서 수신객체(receiver)는 코루틴이므로 함수 내에서 마치 자기 자신이 coroutine인 것처럼 코드를 구현할 수 있다
launch {
this // 코루틴
}
coroutineScope
코르틴 빌더로 suspension function을 코루틴 스코프로 만들어 준다
coroutineScope는 오로지 coroutineBuilder를 호출하기 위해서 존재
- runBlocking과 다르게 현재 스레드를 멈추게 하지 않는다
- 메인 UI스레드에서 runBlocking를 사용하면 현재 스레드를 중단시키므로, 동일한 스레드에서 진행중인(ex.UI작업) 모든 작업이 중지되므로 UI가 응답하지 않게 될 수도 있음
- 메인 UI스레드에서 coroutineScope를 사용하여도 현재 자식들의 코루틴 작업을 완료할때까지 자신(부모)의 코루틴 실행을 일시 완료하지 않는거지, 동일 스레드의 다른 작업이나 다른 코루틴의 작업을 막지 않는다.
- 새 코루틴 스코프를 생성하지 않고, 현재 코루틴의 스코프 내에서 코루틴을 그룹화하여 관리할때 사용
- coroutineScope는 suspend 함수 내에서만 사용할 수 있다
suspend fun doOne() = coroutineScope { // this : 부모 코루틴
launch { // this : 자식 코루틴
println("1!")
}
}
- suspension function에서 coroutineScope(코루틴 빌더)를 호출함으로써 launch(코루틴 빌더)를 호출할 수 있게 되었다
- 또한 coroutineScope 가 만든 코루틴과 내부 launch를 통해 만든 코루틴은 다른 코루틴이다
- coroutineScope가 만든 코루틴은 부모 코루틴, launch가 만든 코루틴은 자식 코루틴이다
- 부모 코루틴이 취소되면 하위에 생성된 자식 코루틴은 모두 취소된다
- 부모 코루틴은 하위에 생성된 자식 코루틴이 모두 실행될때까지 기다린다
Job
코르틴 빌더 launch의 반환 값.
join()이라는 함수를 이용해서 종료될때까지 기다리게 만들 수 있다.
suspend fun doOneTwoThree() = coroutineScope {
val job = launch { println("3!") }
job.join()
launch { println("1!") }
launch { println("2!") }
println("4!")
}
fun main() = runBlocking {
doOneTwoThree()
println("5!")
}
- 결과는 3! 4! 1! 2! 5!
- 3! : join 으로 인해서 첫번째 launch의 코드 블럭이 모두 실행되는 동안 다른 코드 블록은 기다리게 된다
- 4! : 그 다음에 2개의 launch가 있지만 우선적으로는 coroutineScope에 있는 함수가 실행되고, 나머지 두개의 launch는 순서를 기다리고 있는다.
- 1! 2! : 그 다음 순서를 기다리고 있던 launch내에 있는 함수들이 실행된다
- 5! : doOneTwoThree() 내부에 있던 함수들이 모두 실행된 다음에야 runBlocking내부에 있는 함수가 실행된다
- 부모 코루틴은 자식 코루틴이 모두 실행될때까지 기다려 주기 떄문
<가벼운 코루틴>
딜레이가 있을때마다 다른 코루틴에게 thread를 양보하므로 thread를 만드는 부담이 적고, 여러개의 코루틴이 만들어져도 많은 부담이 들지 않는다.
Q. 왜 main함수에서 runBlocking 안에서 doOneTwoThree()함수가 먼저 진행이 되는걸까?
1)
fun main() = runBlocking {
launch { println("World!") }
println("Hello")
}
해당 함수의 결과는 Hello\nWorld!이다.
launch는 비동기 작업을 수행함으로써 두 함수가 동시에 실행되는데, launch 안에 있는 함수는 새로운 코루틴을 실행하는데 시간이 소요되므로 메인 스레드의 코드가 먼저 실행된다
2)
fun man() = runBlocking {
doOneTwoThree() // suspend fun doOneTwoThree() = coroutineScope { }
println("Hello")
}
runBlocking 내부에 suspend 함수는 동기적으로 실행되므로 먼저 선언된 doOneTwoThree가 실행되는것
(suspend함수는 coroutineScope 코루틴 빌더로 구현되어 있어 현재 스레드를 블로킹하지 않지만 runBlocking이 현재 스레드를 블로킹하고 있기 때문에 결과적으로 순차적으로 진행된다. 이로써 coroutineScope도 현재 스레드를 블로킹하는것처럼 보일 수도 있으나 이는 runBlocking이 모든 작업이 완료될때까지 기다리는 특성 때문)
'Android' 카테고리의 다른 글
[Coroutine] 취소와 타임아웃(2) - finally, withContext, withTimeout (0) | 2024.05.06 |
---|---|
[Coroutine] 취소와 타임아웃(1) - cancel (0) | 2024.05.06 |
[Coroutine] 스코프 빌더 - sleep, suspend (0) | 2024.05.04 |
[Coroutine] 스코프빌더 - runBlocking, launch (0) | 2024.05.04 |
[Coroutine] 처음 만나는 코루틴 (0) | 2024.05.04 |