잡,구조화된동시성
suspend 함수에서 코루틴 빌더 호출
import kotlinx.coroutines.*
suspend fun doOneTwoThree() {
launch {
println("launch1: ${Thread.currentThread().name}")
delay(1000L) // suspension Point
println("3!")
}
launch {
println("launch2: ${Thread.currentThread().name}")
println("1!")
}
launch {
println("launch3: ${Thread.currentThread().name}")
delay(500L) // suspension Point
println("2!")
}
println("4!")
}
fun main() = runBlocking {
doOneTwoThree() // suspension Point ( suspend 함수를 썻기 때문 )
println("runBlocking: ${Thread.currentThread().name}")
println("5!")
}
실행결과
Unresolved reference: launch
Suspension functions can be called only within coroutine body
Unresolved reference: launch
Unresolved reference: launch
Suspension functions can be called only within coroutine body
* 코루틴 빌더는 코루틴 스코프 내에서만 호출해야 합니다.
( 위 소스는 동작하지 않을 것이다. launch는 코루틴 스코프 안에서 실행되어야 하기 때문이다. )
* suspension Point 는 잠든 동안에 다른 녀석들에게 양보 할 수 있다.
* expression body 형태로 작성되었다.
그럼 올바르게 수정을 해본다면 ?
=> 코루틴 스코프를 만들 면된다! ( how? 스코프 빌더를 이용하면 됨 )
= > 코루틴 스코프를 만드는 다른 방법은 스코프 빌더를 이용하는 것입니다. coroutineScope를 이용해보세요.
coroutineScope 로 body를 만들어준다.
코루틴 스코프
import kotlinx.coroutines.*
suspend fun doOneTwoThree() = coroutineScope { // 부모 코루틴
launch { // 자식 코루틴
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("3!")
}
launch {
println("launch2: ${Thread.currentThread().name}")
println("1!")
}
launch {
println("launch3: ${Thread.currentThread().name}")
delay(500L)
println("2!")
}
println("4!")
}
fun main() = runBlocking { // 부모코루틴
doOneTwoThree()
println("runBlocking: ${Thread.currentThread().name}")
println("5!")
}
실행결과
4!
launch1: main @coroutine#2
launch2: main @coroutine#3
1!
launch3: main @coroutine#4
2!
3!
runBlocking: main @coroutine#1
5!
코루틴 스코프는 runBlocking을 썼을 때와 모양이 거의 비슷합니다.
하지만 둘의 차이가 있는데
runBlocking은 현재 쓰레드를 멈추게 만들고, 기다리지만 ( withContext 도 비슷 )
coroutineScope는 현재 스레드를 멈추게 하지 않습니다. ( 다른 누군가 일을 하려고하면 일을하게 해준다 )
호출한 쪽이 suspend되고 시간이 되면 다시 활동하게 됩니다.
Job을 이용한 제어
코루틴 빌더 launch는 Job객체를 반환하며 이를 통해 종료될 때까지 기다릴 수 있습니다
- join은 기다리게 한다 ( suspension point 가 된다 ) , job이끈날 때까지 다른 launch에 양보하지 않는다.
import kotlinx.coroutines.*
suspend fun doOneTwoThree() = coroutineScope {
val job = launch {
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("3!")
}
job.join() // suspension Point 위 블록이 끈날때까지 대기시킨다.
// job이 종료된 후 다음진행
launch {
println("launch2: ${Thread.currentThread().name}")
println("1!")
}
launch {
println("launch3: ${Thread.currentThread().name}")
delay(500L)
println("2!")
}
println("4!")
}
fun main() = runBlocking {
doOneTwoThree() // coroutineScope 가 다 끈난 후에 아래 진행
println("runBlocking: ${Thread.currentThread().name}")
println("5!")
}
수행결과
launch1: main @coroutine#2
3!
4!
launch2: main @coroutine#3
1!
launch3: main @coroutine#4
2!
runBlocking: main @coroutine#1
5!
** Join 이 되어있으면 이시점 부터는 기다리고있다 는 것을 기억!
** 부모 코루틴은 (coroutineScope) 는 자식이 다 끈날때까지 기다린다. !
가벼운 코루틴
코루틴은 협력적으로 동작하기 때문에
여러 코루틴을 만드는 것이 큰 비용이 들지 않습니다.
10만개의 간단한 일을 하는 코루틴도 큰 부담은 아닙니다.
(하지만 코틀린 플레이그라운드의 한계로 그렇게 많은 코루틴은 로그를 찍지 못합니다.)
import kotlinx.coroutines.*
suspend fun doOneTwoThree() = coroutineScope {
val job = launch {
println("launch1: ${Thread.currentThread().name}")
delay(1000L)
println("3!")
}
job.join()
launch {
println("launch2: ${Thread.currentThread().name}")
println("1!")
}
repeat(1000) {
launch {
println("launch3: ${Thread.currentThread().name}")
delay(500L)
println("2!")
}
}
println("4!")
}
fun main() = runBlocking {
doOneTwoThree()
println("runBlocking: ${Thread.currentThread().name}")
println("5!")
}
repeat 는 반복해서 실행한다는 의미
'Android 공부 > Coroutine' 카테고리의 다른 글
[XX캠퍼스] 04. Kotlin Coroutines & Flow ( 서스팬딩 함수 ) (0) | 2022.07.22 |
---|---|
[XX캠퍼스] 03. Kotlin Coroutines & Flow ( 취소와 타임아웃 ) (0) | 2022.07.21 |
[XX캠퍼스] 01. Kotlin Coroutines & Flow ( 스코프빌더 ) (0) | 2022.07.19 |
코루틴 Flow 참고 블로그 주소 (0) | 2022.07.16 |
코루틴 기초 정리 _ part 02 Cancellation And Timeouts (0) | 2022.07.16 |