Kotlin【입문-Coroutine①-】

Kotlin【입문-Coroutine①-】

2022-10-05 last update

18 minutes reading coroutine Kotlin

개요



kotlin coroutine에 대해 잡아 보았습니다.

참고 자료:
Coroutine Basics
Cancellation and Timeouts
Composing Suspending Functions

기본 시스템


  • GlobalScope.launch에서 코 루틴 시작 (1 초 중지)
  • println("Hello,")
  • 메인 스레드에서 2초 정지
  • 1.의 1초 정지가 끝나, println("World!")
  • 3. 2 초 정지 종료
  • 응용 프로그램 종료

  • main.kt
    import kotlinx.coroutines.*
    
    fun main() {
      GlobalScope.launch {
          delay(1000L) // コルーチンで1秒停止
          println("World!")
      }
      println("Hello,")
      Thread.sleep(2000L) // メインスレッドで2秒停止
    }
    

    포인트


  • 코루틴은 GlobalScope.launch로 시작합니다.
  • 응용 프로그램이 종료되면 작동하지 않습니다

  • Blocking(블로킹)



    main.kt
    fun main() {
        GlobalScope.launch {
            delay(1000L) // コルーチンで1秒停止 non-blocking
            println("World!")
        }
        println("Hello,")
        runBlocking {
            delay(2000L) // メインスレッドを2秒停止
        }
    }
    
    // 以下のようにすることでも同じ結果を得られる
    fun main() = runBlocking {
        GlobalScope.launch {
            delay(1000L) // コルーチンで1秒停止 non-blocking
            println("World!")
        }
        println("Hello,")
        delay(2000L)
    }
    
    // runBlockingを用いることでコルーチンが終了するまで、アプリケーションの終了を待つことができる
    fun main() = runBlocking {
        val job = GlobalScope.launch {
            delay(1000L)
            println("World!")
        }
        println("Hello,")
        job.join()
    }
    
    // `GlobalScope.launch`ではなく`launch`を用いることでこのスコープ内でコルーチンを起動する
    fun main() = runBlocking {
        launch {
            delay(1000L)
            println("World!")
        }
        println("Hello,")
    }
    

    포인트


  • runBlocking {...}를 사용하면 내부 코루틴이 끝날 때까지 스레드를 차단 (중지) 할 수 있습니다.
  • GlobalScope.launchlaunch로 시작할 범위를 지정할 수 있습니다.

    coroutineScope(스코프)



    main.kt
    fun main() = runBlocking {
        // 処理が完了するまでスレッドを停止する
        launch {
            delay(200L)
            println("Task from runBlocking")
        }
    
        coroutineScope {
            launch {
                delay(500L)
                println("Task from nested launch")
            }
    
            delay(100L)
            println("Task from coroutine scope")
        }
    
        println("Coroutine scope is over")
    }
    

    포인트


  • runBlocking은 블록 (정지), coroutineScope는 일시 정지
  • GlobalScope.launchlaunch로 시작할 범위를 지정할 수 있습니다.

    Cancel(취소)



    main.kt
    fun main() = runBlocking {
        val job = launch {
            repeat(1000) { i ->
                println("job: I'm sleeping $i ...")
                delay(500L)
            }
        }
        delay(1300L)
        println("main: I'm tired of waiting!")
        job.cancel() // jobのキャンセル
        job.join() // job完了を待つ
        println("main: Now I can quit.")
    }
    
    fun main() = runBlocking {
        val job = launch {
          try {
            repeat(1000) { i ->
                println("job: I'm sleeping $i ...")
                delay(500L)
            }
          } finally {
            // 以下のコルーチンはキャンセルされないようにする
            withContext(NonCancellable) {
              println("job: I'm running finally")
              delay(1000L)
              println("job: And I've just delayed for 1 sec because I'm non-cancellable")
            }
          }
        }
        delay(1300L)
        println("main: I'm tired of waiting!")
        job.cancelAndJoin() // jobのキャンセル&完了を待つ
        println("main: Now I can quit.")
    }
    
    

    포인트


  • cancel 메소드에서 job (코 루틴)을 취소 할 수 있습니다
  • join 에서 job (코루틴)의 끝까지 기다린다
  • cancelAndJoin라는 cancel과 join이 합쳐진 메소드도 있다
  • try {...} finally {...}를 사용하여 취소하면 finally 블록을 통과합니다.
  • withContext(NonCancellable) {...}를 사용하여 취소되지 않도록 할 수 있습니다.

    Timeout(타임아웃)



    main.kt
    fun main() = runBlocking {
        withTimeout(1300L) {
            repeat(1000) { i ->
                println("I'm sleeping $i ...")
                delay(500L)
            }
        }
    }
    
    fun main() = runBlocking {
        val result = withTimeoutOrNull(1300L) {
        repeat(1000) { i ->
            println("I'm sleeping $i ...")
            delay(500L)
        }
        "Done" // will get cancelled before it produces this result
      }
      println("Result is $result")
    }
    

    포인트


  • withTimeout에서 job (코 루틴) 제한 시간을 설정할 수 있습니다 (타임 아웃시 예외를 throw합니다.)
  • withTimeoutOrNull 는 타임 아웃시에 null를 돌려줍니다

  • Suspend 함수



    main.kt
    fun main() = runBlocking {
        launch { doWorld() }
        println("Hello,")
    }
    
    // this is your first suspending function
    suspend fun doWorld() {
        delay(1000L)
        println("World!")
    }
    

    main.kt
    suspend fun doSomethingUsefulOne(): Int {
        delay(1000L)
        return 13
    }
    
    suspend fun doSomethingUsefulTwo(): Int {
        delay(1000L)
        return 29
    }
    
    // The answer is 42
    // Completed in 2017 ms
    fun main() = runBlocking {
        val time = measureTimeMillis {
          val one = async { doSomethingUsefulOne() }
          val two = async { doSomethingUsefulTwo() }
          println("The answer is ${one.await() + two.await()}")
        }
        println("Completed in $time ms")
    }
    
    // The answer is 42
    // Completed in 1017 ms
    fun main() = runBlocking {
        val time = measureTimeMillis {
            val one = async { doSomethingUsefulOne() }
            val two = async { doSomethingUsefulTwo() }
            println("The answer is ${one.await() + two.await()}")
        }
        println("Completed in $time ms")
    }
    

    포인트


  • Suspend 한정자를 사용하여 코 루틴 내에서 사용할 수 있습니다 delay
  • suspend 함수는 코 루틴 범위없이 호출 할 수 있습니다
  • async/await 키워드를 사용하여 비동기 처리 할 수 ​​있습니다

  • 마지막으로



    알사가 파트너스 Advent Calendar 2020 22일째는 @miumi 님의 턴입니다.