About Coroutines

creativeBinΒ·2022λ…„ 12μ›” 27일
0

Coroutine (코루틴)

https://www.kodeco.com/34262147-kotlin-coroutines-tutorial-for-android-advanced

What Are Coroutines? 😊

μ“°λ ˆλ“œλ₯Ό λ©ˆμΆ”μ§€ μ•Šκ³  λΉ„λ™κΈ°μ μœΌλ‘œ 코루틴 μŠ€μ½”ν”„ λ‚΄μ—μ„œ 지정해쀀 역할을 μˆ˜ν–‰ν•¨.

Coroutines Builder

Coroutines Builder

μƒˆ 코루틴을 μ‹œμž‘ν•˜κ³  μ‹€ν–‰ν•˜λ €λ©΄ 코루틴 λΉŒλ”λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•©λ‹ˆλ‹€. 그듀은 일뢀 μ½”λ“œλ₯Ό 가져와 μ½”λ£¨ν‹΄μœΌλ‘œ λž˜ν•‘ν•˜μ—¬ 싀행을 μœ„ν•΄ μ‹œμŠ€ν…œμ— μ „λ‹¬ν•©λ‹ˆλ‹€.

μ¦‰μ‹œ μ‹€ν–‰ (launch)

μ½”λ£¨ν‹΄μ˜ κΈ°λ³Έ λΉŒλ”λŠ” launch() μž…λ‹ˆλ‹€. μƒˆ 코루틴을 μƒμ„±ν•˜κ³  기본적으둜 μ¦‰μ‹œ μ‹€ν–‰ν•©λ‹ˆλ‹€. 일뢀 CoroutineScope μ»¨ν…μŠ€νŠΈμ—μ„œ 코루틴을 λΉŒλ“œν•˜κ³  μ‹œμž‘ν•©λ‹ˆλ‹€.

GlobalScope.launch { // CoroutineScope
  // coroutine body
}

λ™μ‹œ μ‹€ν–‰ (Async)

μ€‘μ²©λœ 코루틴을 μ‹œμž‘ν•˜λŠ” 기타 μΌμ‹œ 쀑지 κ°€λŠ₯ν•œ ν•¨μˆ˜μ—μ„œ Coroutines Builderλ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ™μ‹œ μ‹€ν–‰
또 λ‹€λ₯Έ 코루틴 λΉŒλ”λŠ” async(). μ½”λ£¨ν‹΄μ—μ„œ 값을 λ°˜ν™˜ν•˜λŠ” 데 μ‚¬μš©ν•  수 있기 λ•Œλ¬Έμ— νŠΉλ³„ν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ λ™μ‹œ 싀행이 κ°€λŠ₯ν•©λ‹ˆλ‹€. async()λ‹€μŒκ³Ό 같이 λͺ¨λ“  μ½”λ£¨ν‹΄μ—μ„œ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€ .

GlobalScope.launch { // CoroutineScope 
  val someValue = async { getValue() } // μ½”λ£¨ν‹΄μ—μ„œ κ³„μ‚°λœ κ°’ 
}

κ·ΈλŸ¬λ‚˜ 아직 값을 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€. 비차단 μ·¨μ†Œ κ°€λŠ₯ ν“¨μ²˜μΈ async()aλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€ . Deferred κ²°κ³Όλ₯Ό μ–»μœΌλ €λ©΄ λ₯Ό ν˜ΈμΆœν•΄μ•Ό ν•©λ‹ˆλ‹€ await(). 기닀리기 μ‹œμž‘ν•˜λ©΄ κ³„μ‚°λœ 값을 얻을 λ•ŒκΉŒμ§€ λž˜ν•‘ 코루틴을 μΌμ‹œ μ€‘μ§€ν•©λ‹ˆλ‹€.

λΈ”λ‘œν‚Ή λΉŒλ” (runBlocking)

μ•½κ°„ 색닀λ₯Έ μ½”λ£¨ν‹΄μš© λ‹€λ₯Έ λΉŒλ”λ₯Ό μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€. runBlocking() 코루틴이 ν˜ΈμΆœμ„ μ°¨λ‹¨ν•˜λ„λ‘ ν•©λ‹ˆλ‹€.

runBlocking 은 메인 κΈ°λŠ₯μ΄λ‚˜ ν…ŒμŠ€νŠΈμ™€ 같은 νŠΉλ³„ν•œ μƒν™©μ—μ„œ JVM μ’…λ£Œλ₯Ό ν”Όν•˜κΈ° μœ„ν•΄ 싀행이 μ™„λ£Œλ  λ•ŒκΉŒμ§€ μŠ€λ ˆλ“œλ₯Ό μ°¨λ‹¨ν•˜λŠ” λΉŒλ”μž…λ‹ˆλ‹€. 일반 Kotlin 코루틴 μ½”λ“œμ—μ„œλŠ” μ‚¬μš©ν•˜μ§€ μ•Šμ•„μ•Ό ν•©λ‹ˆλ‹€.

Kotlin 코루틴을 μ‹œμž‘ν•˜κ³  μ‹€ν–‰ν•˜λŠ” 방법을 μ„€λͺ…ν•˜λ €λ©΄ λͺ‡ 가지 라이브 μ½”λ“œ μŠ€λ‹ˆνŽ«μ„ μ‚΄νŽ΄λ³΄λŠ” 것이 κ°€μž₯ μ’‹μŠ΅λ‹ˆλ‹€.

Kotlin Playground

import kotlinx.coroutines.*
import java.lang.Thread

@OptIn(DelicateCoroutinesApi::class)
fun main() {
  GlobalScope.launch {  // launch new coroutine in background and continue
    delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
    println("World!") // print after delay
    val sum1 = async { // non blocking sum1
      delay(100L)
      2 + 2
    }
    val sum2 = async { // non blocking sum2
      delay(500L)
      3 + 3
    }
    println("waiting concurrent sums")
    val total = sum1.await() + sum2.await() // execution stops until both sums are calculated
    println("Total is: $total")
  }
  println("Hello,")     // main thread continues while coroutine executes
  Thread.sleep(2000L)   // block main thread for 2 seconds to keep JVM alive
}

console을 확인해보면

Hello,
World!
waiting concurrent sums
Total is: 10

이와 같이 λ‚˜μ˜€κ²Œλ©λ‹ˆλ‹€.

delay() μœ„μ˜ μŠ€λ‹ˆνŽ« 은 1초 λ™μ•ˆ κΈ°λŠ₯을 μΌμ‹œ 쀑단 ν•˜λŠ” 데 μ‚¬μš©ν•˜λŠ” Kotlin 코루틴을 μ‹œμž‘ν•©λ‹ˆλ‹€ .

Kotlin 코루틴은 μŠ€λ ˆλ“œλ₯Ό μ°¨λ‹¨ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μ½”λ“œλŠ” 두 번째 println()λͺ…λ Ήλ¬Έ 으둜 μ§„ν–‰ν•˜μ—¬ 1) Hello,.

λ‹€μŒμœΌλ‘œ μ½”λ“œλŠ” 메인 μŠ€λ ˆλ“œλŠ” 잠자기 λ•Œλ¬Έμ— 코루틴이 싀행을 μ™„λ£Œν•˜κΈ° 전에 ν”„λ‘œκ·Έλž¨μ΄ μ™„λ£Œλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

코루틴은 두 번째 쀄을 μ‹€ν–‰ν•˜κ³  λ₯Ό μΈμ‡„ν•©λ‹ˆλ‹€ 2) World!.

그런 λ‹€μŒ 두 개의 비동기 코루틴 을 λ™μ‹œμ— λΉŒλ“œν•˜κ³  μ‹œμž‘ν•©λ‹ˆλ‹€. λ§ˆμ§€λ§‰μœΌλ‘œ 두 λ™μ‹œ μž‘μ—…μ΄ λͺ¨λ‘ μ™„λ£Œλ˜λ©΄ 3) 합계가 좜λ ₯λ©λ‹ˆλ‹€.

CoroutineScope

CoroutineScope 코루틴에 λ°”μΈλ”©λ˜λŠ” 수λͺ… μ£ΌκΈ° 바인딩 ꡬ성 μš”μ†Œλ₯Ό μ œκ³΅ν•˜μ—¬
μƒˆ 코루틴을 μ œν•œν•©λ‹ˆλ‹€.

λͺ¨λ“  코루틴 λΉŒλ”λŠ” CoroutineScope μœ ν˜•μ— μ •μ˜λœ ν™•μž₯ ν•¨μˆ˜μž…λ‹ˆλ‹€.

Android μ•±μ—μ„œλŠ” CoroutineScope 수λͺ… μ£ΌκΈ°κ°€ 잘 μ •μ˜λœ ꡬ성 μš”μ†Œλ₯Ό κ΅¬ν˜„ν•©λ‹ˆλ‹€.

ꡬ성 μš”μ†Œμ—λŠ” Activity, Fragment, ViewModel

Job λ²”μœ„κ°€ μ·¨μ†Œλ˜λ©΄ λͺ¨λ“  Kotlin 코루틴이 λ¦¬μ†ŒμŠ€λ₯Ό μ •λ¦¬ν•˜κ³  μ·¨μ†Œν•©λ‹ˆλ‹€.

import kotlinx.coroutines.*
import java.lang.Thread

fun main() = runBlocking { // this: CoroutineScope
  launch { 
    delay(200L)
    println("Task from runBlocking")
  }

  coroutineScope { // Creates a new coroutine scope
    val job = launch {
      println("Task from nested launch, this is printed")
      delay(500L) 
      println("Task from nested launch, this won't be printed")
    }

    delay(100L)
    println("Task from first coroutine scope") // Printed before initial launch
    job.cancel() // This cancels nested launch's execution
  }
    
  println("Coroutine scope is over") // This is not printed until nested launch completes/is cancelled
}
Task from nested launch, this is printed
Task from first coroutine scope
Coroutine scope is over
Task from runBlocking

console을 μ‚΄νŽ΄λ³΄λ©΄ λͺ‡ 가지λ₯Ό μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

첫째, 코루틴을 κ°•μ œλ‘œ μ°¨λ‹¨ν•˜λ―€λ‘œ μ΄μ „μ²˜λŸΌ ν”„λ‘œκ·Έλž¨μ„ 휴면(잠자기) μƒνƒœλ‘œ λ‘˜ ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

  • 초기 지연이 μžˆλŠ” μƒˆ 코루틴을 μ‹œμž‘ν•©λ‹ˆλ‹€.
  • coroutineScope()λ₯Ό μ‚¬μš©ν•˜μ—¬ μƒˆ λ²”μœ„λ₯Ό λ§Œλ“­λ‹ˆλ‹€.
  • κ·Έ μ•ˆμ—μ„œ 코루틴을 μ‹œμž‘ν•˜μ—¬ λ°˜ν™˜λœ μž‘μ—…μ„ μ €μž₯ν•©λ‹ˆλ‹€.
  • 초기 launch()λ₯Ό μ§€μ—°μ‹œν‚€κΈ° λ•Œλ¬Έμ— coroutineScope() μ™„μ „νžˆ 싀행될 λ•ŒκΉŒμ§€ μ‹€ν–‰λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

κ·ΈλŸ¬λ‚˜ coroutineScope() λ‚΄μ—μ„œ μž‘μ—…κ³Ό μ€‘μ²©λœ 코루틴을 μ €μž₯ν•˜κ³  μ§€μ—°ν•©λ‹ˆλ‹€.
μ§€μ—°λœ 후에 μ·¨μ†Œν•˜κΈ° λ•Œλ¬Έμ— 첫 번째 문만 좜λ ₯ν•˜κ³ 

ꢁ극적으둜 두 번째 좜λ ₯ 전에 μ·¨μ†Œν•©λ‹ˆλ‹€. 그리고 coroutineScope()κ°€ μ™„λ£Œλ˜λ©΄

초기 launch()κ°€ 지연을 끝내고 싀행을 계속할 수 μžˆμŠ΅λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ λ²”μœ„κ°€ μ™„λ£Œλ˜λ©΄ runBlocking()도 μ™„λ£Œλ  수 μžˆμŠ΅λ‹ˆλ‹€.

μ΄κ²ƒμœΌλ‘œ ν”„λ‘œκ·Έλž¨μ΄ μ’…λ£Œλ©λ‹ˆλ‹€. κ²½ν•© μƒνƒœλ‚˜ μ€‘λ‹¨λœ λ¦¬μ†ŒμŠ€ 없이

μ•ˆμ •μ μΈ 코루틴을 κ΅¬μΆ•ν•˜λ €λ©΄ 이 μ‹€ν–‰ 흐름을 μ΄ν•΄ν•˜λŠ” 것이 μ€‘μš”ν•©λ‹ˆλ‹€.

Canceling a Job

이전 μ„Ήμ…˜μ—μ„œ 코루틴 싀행을 μ·¨μ†Œν•˜λŠ” 방법을 μ‚΄νŽ΄λ³΄μ•˜μŠ΅λ‹ˆλ‹€.
μž‘μ—…μ€ 수λͺ… μ£ΌκΈ°κ°€ μžˆλŠ” μ·¨μ†Œ κ°€λŠ₯ν•œ ꡬ성 μš”μ†Œμž„μ„ 이해해야 ν•©λ‹ˆλ‹€.

  • μž‘μ—…μ€ 일반적으둜 launch()λ₯Ό ν˜ΈμΆœν•˜μ—¬ μƒμ„±λ©λ‹ˆλ‹€.
  • μƒμ„±μž Job()을 μ‚¬μš©ν•˜μ—¬ 생성할 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

λ‹€λ₯Έ μž‘μ—…μ˜ 계측 ꡬ쑰 λ‚΄μ—μ„œ λΆ€λͺ¨ λ˜λŠ” μžμ‹μœΌλ‘œ μ‚΄ 수 μžˆμŠ΅λ‹ˆλ‹€.
μƒμœ„ μž‘μ—…μ„ μ·¨μ†Œν•˜λ©΄ λͺ¨λ“  ν•˜μœ„ μž‘μ—…λ„ μ·¨μ†Œλ©λ‹ˆλ‹€.

ν•˜μœ„ μž‘μ—…μ΄ μ‹€νŒ¨ν•˜κ±°λ‚˜ μ·¨μ†Œλ˜λ©΄ μƒμœ„ 및 μƒμœ„ 계측 ꡬ쑰도 μ·¨μ†Œλ©λ‹ˆλ‹€.
계측이 λ°›λŠ” μ˜ˆμ™ΈλŠ” λ¬Όλ‘  CancellationExceptionμž…λ‹ˆλ‹€.

μžμ‹μ΄ μ‹€νŒ¨ν•˜λ©΄ 기본적으둜 λΆ€λͺ¨μ™€ 계측 ꡬ쑰의 λ‹€λ₯Έ λͺ¨λ“  μžμ‹μ΄ μ·¨μ†Œλ©λ‹ˆλ‹€. λ•Œλ‘œλŠ” 코루틴 싀행이 효과적으둜 μ·¨μ†Œλ  λ•ŒκΉŒμ§€ κΈ°λ‹€λ €μ•Ό ν•©λ‹ˆλ‹€. 이 경우 job.cancel() λŒ€μ‹  job.cancelAndJoin()을 ν˜ΈμΆœν•  수 μžˆμŠ΅λ‹ˆλ‹€.

import java.lang.Thread
import kotlinx.coroutines.*

fun main() = runBlocking {
  val startTime = System.currentTimeMillis()
  val job = launch(Dispatchers.Default) {
    var nextPrintTime = startTime
    var i = 0
    while (isActive) { // cancelable computation loop
      // print a message twice a second
      if (System.currentTimeMillis() >= nextPrintTime) {
        println("I'm sleeping ${i++} ...")
        nextPrintTime += 500L
      }
    }
  }
  delay(1300L) // delay a bit
  println("main: I'm tired of waiting!")
  job.cancelAndJoin() // cancels the job and waits for its completion
  println("main: Now I can quit.")    
}
I'm sleeping 0 ...
I'm sleeping 1 ...
I'm sleeping 2 ...
main: I'm tired of waiting!
main: Now I can quit.

CoroutinesDispatchers

DispatcherλŠ” 코루틴이 싀행을 μœ„ν•΄ μ‚¬μš©ν•˜λŠ” μŠ€λ ˆλ“œ λ˜λŠ” μŠ€λ ˆλ“œ 풀을 κ²°μ •ν•©λ‹ˆλ‹€.
λ””μŠ€νŒ¨μ²˜λŠ” 코루틴을 νŠΉμ • μŠ€λ ˆλ“œλ‘œ μ œν•œν•  수 μžˆμŠ΅λ‹ˆλ‹€.
μŠ€λ ˆλ“œ ν’€λ‘œ 보낼 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
ν”ν•˜μ§€λŠ” μ•Šμ§€λ§Œ μ˜ˆμΈ‘ν•  수 μ—†λŠ” νŠΉμ • μŠ€λ ˆλ”© κ·œμΉ™ 없이 코루틴을 μ œν•œ 없이 μ‹€ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λ‹€μŒμ€ λͺ‡ 가지 일반적인 λ””μŠ€νŒ¨μ²˜μž…λ‹ˆλ‹€.

  • Dispatchers.Main
    코루틴을 Swing, JavaFX λ˜λŠ” Android μ•±κ³Ό 같은 UI 기반 ν”„λ‘œκ·Έλž¨μ˜ κΈ°λ³Έ μŠ€λ ˆλ“œλ‘œ μ œν•œν•©λ‹ˆλ‹€. 이 λ””μŠ€νŒ¨μ²˜λŠ” Gradle λ˜λŠ” Mavenμ—μ„œ ν™˜κ²½λ³„ Main λ””μŠ€νŒ¨μ²˜ 쒅속성을 μΆ”κ°€ν•˜μ§€ μ•ŠμœΌλ©΄ μž‘λ™ν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 점에 μœ μ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.
    UI와 μƒν˜Έμž‘μš©ν•˜λŠ” μž‘μ—…μ„ μ‹€ν–‰ν•˜κΈ° μœ„ν•΄μ„œλ§Œ μ‚¬μš©ν•΄μ•Όν•¨

  • Dispatchers.Default
    ν‘œμ€€ λΉŒλ”μ—μ„œ μ‚¬μš©ν•˜λŠ” κΈ°λ³Έ λ””μŠ€νŒ¨μ²˜μž…λ‹ˆλ‹€. JVM μŠ€λ ˆλ“œμ˜ 곡유 풀이 μ§€μ›ν•©λ‹ˆλ‹€. CPU 집약적 계산에 이 λ””μŠ€νŒ¨μ²˜λ₯Ό μ‚¬μš©ν•˜μ‹­μ‹œμ˜€.
    CPUλ₯Ό 많이 μ‚¬μš©ν•˜λŠ” μž‘μ—…μ„ κΈ°λ³Έ μŠ€λ ˆλ“œ μ™ΈλΆ€μ—μ„œ μ‹€ν–‰ν•˜λ„λ‘ μ΅œμ ν™”

  • Dispatchers.IO
    곡유 μŠ€λ ˆλ“œ 풀을 μ‚¬μš©ν•˜λŠ” I/O 집쀑 차단 μž‘μ—…μ— 이 λ””μŠ€νŒ¨μ²˜λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.
    λ””μŠ€ν¬ λ˜λŠ” λ„€νŠΈμ›Œν¬I/O μž‘μ—…μ„ μ‹€ν–‰ν•˜λŠ”λ° μ΅œμ ν™”

  • Dispatchers.Unconfined
    이 λ””μŠ€νŒ¨μ²˜λŠ” 코루틴을 νŠΉμ • μŠ€λ ˆλ“œλ‘œ μ œν•œν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 코루틴은 μžμ‹ μ„ ν˜ΈμΆœν•œ μƒμ†λœ CoroutineDispatcherμ—μ„œ 싀행을 μ‹œμž‘ν•˜μ§€λ§Œ 첫 번째 정지 μ§€μ κΉŒμ§€λ§Œ μ‹€ν–‰λ©λ‹ˆλ‹€. μΌμ‹œ 쀑단이 λλ‚˜λ©΄ 호좜된 μΌμ‹œ 쀑단 ν•¨μˆ˜μ— μ˜ν•΄ μ™„μ „νžˆ κ²°μ •λœ μŠ€λ ˆλ“œμ—μ„œ λ‹€μ‹œ μ‹œμž‘λ©λ‹ˆλ‹€.

import java.lang.Thread
import kotlinx.coroutines.*

@OptIn(DelicateCoroutinesApi::class)
fun main() = runBlocking<Unit> {
  launch { //context of the parent, main runBlocking coroutine
    println("main runBlocking: I'm working in thread ${Thread.currentThread().name}")
  }
  launch(Dispatchers.Unconfined) { //not confined -- will inmediatly run in main thread but not after suspension
    println("Unconfined: I'm working in thread ${Thread.currentThread().name}")
    delay(100L) // delays (suspends) execution 100 ms
    println("Unconfined: I'm working in thread ${Thread.currentThread().name}")
  }
  launch(Dispatchers.Default) { //will get dispatched to DefaultDispatcher 
    println("Default: I'm working in thread ${Thread.currentThread().name}")
  }
  launch(newSingleThreadContext("MyOwnThread")) {// will get its own new thread
    println("newSingleThreadContext: I'm working in thread ${Thread.currentThread().name}")
  }    
}
Unconfined: I'm working in thread main @coroutine#3
Default: I'm working in thread DefaultDispatcher-worker-1 @coroutine#4
main runBlocking: I'm working in thread main @coroutine#2
newSingleThreadContext: I'm working in thread MyOwnThread @coroutine#5
Unconfined: I'm working in thread kotlinx.coroutines.DefaultExecutor @coroutine#3

Handling Exceptions

μŠ€λ ˆλ“œμ—μ„œ ν¬μ°©λ˜μ§€ μ•Šμ€ μ˜ˆμ™Έκ°€ λ°œμƒν•˜λ©΄ JVM은 μŠ€λ ˆλ“œμ—μ„œ UncaughtExceptionHandlerλ₯Ό μΏΌλ¦¬ν•©λ‹ˆλ‹€. 그런 λ‹€μŒ JVM은 μ’…λ£Œ μŠ€λ ˆλ“œμ™€ ν¬μ°©λ˜μ§€ μ•Šμ€ μ˜ˆμ™Έλ₯Ό μ „λ‹¬ν•©λ‹ˆλ‹€. μ΄λŠ” 코루틴과 Java λ™μ‹œμ„±μ΄ λ™μΌν•œ μ˜ˆμ™Έ λ™μž‘μ„ μ²˜λ¦¬ν•˜κΈ° λ•Œλ¬Έμ— μ€‘μš”ν•©λ‹ˆλ‹€.

코루틴 λΉŒλ”λŠ” 두 가지 μ˜ˆμ™Έ λ²”μ£Όλ‘œ λ‚˜λ‰©λ‹ˆλ‹€.
첫 λ²ˆμ§ΈλŠ” launch()와 같이 μžλ™μœΌλ‘œ μ „νŒŒλ˜λ―€λ‘œ λ‚˜μœ 일이 λ°œμƒν•˜λ©΄ 곧 μ•Œκ²Œ 될 κ²ƒμž…λ‹ˆλ‹€. 두 λ²ˆμ§ΈλŠ” async()와 같이 μ‚¬μš©μžκ°€ μ²˜λ¦¬ν•  μ˜ˆμ™Έλ₯Ό λ…ΈμΆœν•©λ‹ˆλ‹€. 값을 μ–»κΈ° μœ„ν•΄ await()λ₯Ό ν˜ΈμΆœν•  λ•ŒκΉŒμ§€ μ „νŒŒλ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

import java.lang.Thread
import kotlinx.coroutines.*

@OptIn(DelicateCoroutinesApi::class)
fun main() = runBlocking<Unit> {
  // propagating exception to the default Thread.UncaughtExceptionHandler
  val job = GlobalScope.launch {
    // throw AssertionError() -> 주석 ON/OFF Output 확인 !!!
  }

  // blocks thread execution until coroutine completes
  job.join()

  // launches async coroutine but exception is not propagated until await is called
  val deferred = GlobalScope.async(Dispatchers.Default) {
    throw AssertionError()
  }

  //defines a specific handler
  val handler = CoroutineExceptionHandler { _, exception -> 
    println("We caught $exception") 
  }

  // propagating exception using a custom CoroutineExceptionHandler
  GlobalScope.launch(handler) {
    throw AssertionError()
  } 

  // This exception is finally propagated calling await and should be handled by user, eg. with try {} catch {}
  deferred.await() 
}
# 첫번째 쀄 주석 ν’€μ—ˆμ„ 경우
Exception in thread "DefaultDispatcher-worker-1 @coroutine#2" java.lang.AssertionError
	at FileKt$main$1$job$1.invokeSuspend(File.kt:8)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
	at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
	Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [CoroutineId(2), "coroutine#2":StandaloneCoroutine{Cancelling}@14d300bf, Dispatchers.Default]
We caught java.lang.AssertionError
Exception in thread "main" java.lang.AssertionError
 at FileKt$main$1$deferred$1.invokeSuspend (File.kt:16) 
 at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) 
 at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106) 
# 첫번째 쀄 주석일 경우

We caught java.lang.AssertionError
Exception in thread "main" java.lang.AssertionError
 at FileKt$main$1$deferred$1.invokeSuspend (File.kt:16) 
 at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith (ContinuationImpl.kt:33) 
 at kotlinx.coroutines.DispatchedTask.run (DispatchedTask.kt:106) 

Handling 작힌 console을 확인 ν•  수 μžˆλ‹€.

원문

profile
μ–Έμ œλ‚˜ 항상 즐겁게 New vibes 😎

0개의 λŒ“κΈ€