Java/Kotlin

[Coroutine] 코루틴 학습 - 3 (Coroutine Builders)

Icarus8050 2022. 4. 27. 08:16
반응형

Coroutine builders

  • 일시중단 함수는 다른 일시중단 함수을 호출할 때 continuation 객체를 넘겨야 한다.
  • 일시중단 함수 내에서 일반 함수를 호출할 수 있다.
  • 일반 함수는 일시중단 함수를 호출할 수 없다.
  • 즉, 모든 일시중단 함수는 다른 일시중단 함수에 의해 호출되어야 한다.

 

그렇다면 이 일시중단 함수를 최초에 호출할 때 누군가는 호출을 해야할텐데, 어디에서 호출이 가능할까?

  • coroutine builder를 이용하면 일반 함수에서 일시중단 함수를 호출할 수 있도록 징검다리 역할을 해준다.
  • kotlinx.coruotines 라이브러리에서 세 가지 coroutine builder를 지원한다.
    • launch
    • runBlocking
    • async

 

launch builder

  • launch는 개념상 새로운 쓰레드를 시작하여 동작하는 것과 유사하다.
  • coroutine이 시작되면 독립적으로 동작을 수행한다.
fun main() {
    GlobalScope.launch {
        delay(1000L)
        println("World!")
    }
    GlobalScope.launch {
        delay(1000L)
        println("World!")
    }
    GlobalScope.launch {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    Thread.sleep(2000L)
}
// Hello,
// (1 sec..)
// World!
// World!
// World!
  • launch 함수는 CoroutineScpoe 인터페이스의 확장 함수이다.
  • CoroutineScope는 부모 코루틴과 자식 코루틴 간에 관계를 구축하기 위한 목적으로, structured concurrency라고 부르는 중요한 메커니즘이다.
  • 예제 코드에서는 GlocalScope를 사용했지만 실제 프로젝트에서는 사용을 지양해야 한다. (그 이유는 나중에 포스팅할 예정)
  • 예제 코드에서 코루틴의 delay 일시중단 함수가 끝나기 전에 main 함수가 종료되는 것을 방지하기 위해 Thread.sleep()을 호출하여 쓰레드를 잠시 sleep 시켜둔 것을 확인할 수 있다. delay 함수와 같은 일시중단 함수는 쓰레드를 블로킹하지 않기 때문에 메인 쓰레드가 종료되면 프로세스가 종료되어 버리기 때문이다.
  • 이는 데몬 쓰레드를 생성하여 실행하는 모습과 비슷하지만, 코루틴은 쓰레드를 생성하여 실행하는 것보다 훨씬 비용이 저렴하다.

 

runBlocking builder

  • launch builder 에서 살펴보았듯이 블로킹이 필요한 경우도 존재하는데, runBlocking을 이용하면 된다.
  • runBlocking은 코루틴이 일시중단될 때마다 시작된 쓰레드를 블로킹한다.
  • 다른 일반적인 유즈케이스는 단위 테스트에서 위와 동일한 이유로 쓰레드를 블로킹해야 할 때이다.
fun main() {
    runBlocking {
        delay(1000L)
        println("World!")
    }
    runBlocking {
        delay(1000L)
        println("World!")
    }
    runBlocking {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
}
// (1 sec)
// World!
// (1 sec)
// World!
// (1 sec)
// World!
// Hello,

 

async builder

  • async builder는 launch와 유사하지만, 값을 생산하여 반환하도록 설계되었다는 점에서 차이점이 있다.
  • async 함수는 Deffered<T> 타입의 객체를 반환하는데, T 타입은 async 함수에 의해 생산되는 값의 타입이다.
  • Deffered는 await()이라는 일시중단 함수를 가지고 있는데, 값을 반환할 준비가 되면 해당 값을 리턴하게 된다.
  • async builder는 두 가지의 일을 동시에 병렬적 수행하여 데이터를 응답받을 때 종종 사용된다.
fun main() = runBlocking {
    val resultDeferred: Deferred<Int> = GlobalScope.async {
        delay(1000L)
        200
    }

    println("Before")
    val result: Int = resultDeferred.await()
    println("After")
    println(result)
}
// Before
// (1 sec)
// After
// 200

참고자료

https://www.amazon.com/Kotlin-Coroutines-Deep-Marcin-Moskala/dp/8396395837

반응형