Android 공부/Coroutine

[XX캠퍼스] 02. Kotlin Coroutines & Flow ( 잡,구조화된동시성 )

Machine_웅 2022. 7. 20. 17:15
728x90
반응형

잡,구조화된동시성

 

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 는 반복해서 실행한다는 의미

 

728x90
반응형