Kotlin

[2] Kotiln Coroutines - Cancelation / TimeOut

λ„μΊλ¦¬πŸ± 2021. 7. 26. 14:07
λ°˜μ‘ν˜•

https://medium.com/@limgyumin/%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%BD%94%EB%A3%A8%ED%8B%B4%EC%9D%98-%EA%B8%B0%EC%B4%88-cac60d4d621b

도움이 많이 λ˜μ—ˆλ‹€. 

 

μ½”ν‹€λ¦° μ½”λ£¨ν‹΄μ˜ 기초

μ½”ν‹€λ¦° 의 코루틴은 비동기 ν”„λ‘œκ·Έλž˜λ°μ„ μ²˜λ¦¬ν• μˆ˜ μžˆλŠ” 쒋은 λ°©λ²•μž…λ‹ˆλ‹€.

medium.com

 

Dispatcher

 

 

Ref.

Youtube :  [μƒˆμ°¨μ›, μ½”ν‹€λ¦° 코루틴] https://youtube.com/playlist?list=PLbJr8hAHHCP5N6Lsot8SAnC28SoxwAU5A

Ref : https://kotlinlang.org/

 

 

 

 

Cancelation

μ‹€ν–‰ ν–ˆλ˜ 코루틴을 μ·¨μ†Œ ν•˜λŠ” 방법 → μ·¨μ†Œ ν•˜λŠ” 것이 μ€‘μš”ν•œ μ΄μœ λŠ” ν•˜λ‚˜ν•˜λ‚˜ λ©”λͺ¨λ¦¬μ™€ λ¦¬μ†ŒμŠ€λ₯Ό μ°¨μ§€ν•˜κ³  있기 λ•Œλ¬Έ

 μ½”루틴 μ·¨μ†Œμ˜ 쑰건
1) Cancel 호좜
2) 코루틴 μžμ²΄κ°€ μ·¨μ†Œμ— λŒ€ν•΄ ν˜‘μ‘°μ μΈ μƒνƒœλ‘œ κ΅¬ν˜„λ˜μ–΄μžˆμ–΄μ•Όν•¨.

// λ‹¨μˆœ 코루틴 μ·¨μ†Œ
// job κ°μ²΄λŠ” μ‹€ν–‰λ˜κ³  μžˆλŠ” 코루틴을 μ·¨μ†Œν•˜κ²Œλ„ ν•΄μ£ΌλŠ” κΈ°λŠ₯을 가지고 있음
fun main() = runBlocking{
    //  이 코루틴은 1000λ²ˆμ„ λŒλ©΄μ„œ 0.5초 κ°„κ²©μœΌλ‘œ 숫자λ₯Ό 좜
    val job = launch {
        repeat(1000){
            println("job: I'm sleeping ${it}...")
            delay(500L) //suspend func
        }
    }

    delay(1300L)
    println("main : I'm Tired of waiting")
    job.cancel() // 1.3초 정도 μ§€λ‚˜λ©΄ 이 APP 이 λλ‚¬μœΌλ©΄ μ’‹κ² μŒ.
    job.join()
    println("main : Now i can quit.")
}

 

 

/ 코루틴 μ·¨μ†Œμ˜ 쑰건 - supending functions 은 μ·¨μ†Œ κ°€λŠ₯ν•˜λ‹€.
// suspend ν•¨μˆ˜λ₯Ό ν•˜λ‚˜λΌλ„ 두지 μ•ŠμœΌλ©΄ ν•΄λ‹Ή 코루틴은 μ‹€ν–‰ μ·¨μ†Œ ν•  수 μ—†λ‹€.
fun main() = runBlocking {
    val startTime = System.currentTimeMillis()
    val job = launch(Dispatchers.Default){
        var nextPrintTime = startTime
        var i = 0
        while(i < 5){
            if (System.currentTimeMillis() >= nextPrintTime){
                 yield() // suspend func : λ”œλ ˆμ΄λ₯Ό 주지 μ•Šκ³ λ„ μ’…λ£Œλ₯Ό 체크 ν•  수 있음
                // delay(1L)  suspend func 이 λ°˜λ“œμ‹œ
                println("job: I'm sleeping ${i++}...")
                nextPrintTime += 500L
            }
        }
    }
    delay(1300L)
    println("main : I'm tired of waiting")
    job.cancelAndJoin() // cancel κ³Ό join 을 순차적으둜 λΆˆλŸ¬μ£ΌλŠ” ν•¨μˆ˜
    // cancel λ˜μ„œ μΌμ‹œ 쀑단 ν•¨μˆ˜(yield λ‚˜ delay)μ• μ„œ μΌμ‹œ 쀑단이 λ˜μ—ˆλ‹€κ°€ 재개 λ λ•Œ, exception을 λ˜μ§„λ‹€.
    println("main : Now i can quit")
}

 

 

 

 

isActive

// 코루틴이 μ·¨μ†Œ 되기 μœ„ν•΄μ„œ ν˜‘μ‘°μ μΈ 방법을 μ·¨ν•˜λŠ”λ° 크게 2가지 방법이 μžˆλŠ”λ° 2번째 방법은?
// ( 첫번째 방법은 μœ„μ—μ„œ λ΄€λ–€ 주기적으둜 suspending ν˜ΈμΆœν•΄λΌ / λ‘λ²ˆμ§Έ 방법은 λͺ…μ‹œμ μœΌλ‘œ μƒνƒœλ₯Ό 체크 ν•˜μ—¬ _isActive_둜)
// isActive : CourouineScope의 Boolean κ°’
// exception 을 λ˜μ§€μ§€λŠ” μ•ŠλŠ”λ‹€.
fun main() = runBlocking {

    val startTime = System.currentTimeMillis()

    val job = launch(Dispatchers.Default){
        var nextPrintTime = startTime
        var i = 0
        while(isActive){
            if(System.currentTimeMillis() >= nextPrintTime){
                println("job : I'm Sleeping ${i++} ..")
                nextPrintTime +=500L
            }
        }
    }

    delay(1300L)
    println("main : Tired waiting")
    job.cancelAndJoin()
    println("main : Now I can quit")
}

 

 

finally

: λ„€νŠΈμ›Œν¬λ‚˜ DB μ“°λ‹€κ°€ κ°‘μžκΈ° 코루틴 μΊ”μŠ¬ λ˜λŠ” λ“±μ˜ 일이 μžˆμ„ λ•Œ, λ‹«μ•„μ£ΌλŠ” μœ„μΉ˜

// 코루틴을 μ’…λ£Œν•  λ•Œ, μ–΄λ–»κ²Œ λ¦¬μ†ŒμŠ€λ₯Ό ν•΄μ œ ν•˜μ—¬ 쀄 수 μžˆλŠ”κ°€?
// λ„€νŠΈμ›Œν¬λ‚˜ DBλ₯Ό μ“°λ‹€κ°€ κ°‘μžκΈ° 코루틴 cancel 되면 이 νŒŒμΌμ„ λ‹«μ•„μ£Όκ³  κ°€μ•Ό ν•˜λŠ”λ°, 이 λ‹«μ•„μ£ΌλŠ” μœ„μΉ˜κ°€ 어디인가? λ‹«μ•„μ£ΌλŠ” 건 finally
fun main() = runBlocking {

    val job = launch(Dispatchers.Default){
       try{
           repeat(1000){
               i -> println("job: I'm sleeping ${i} ...")
               val curTime  = System.currentTimeMillis() // 1970λ…„ 1/1일 λΆ€ν„° κ²½κ³Όν•œ μ‹œκ°„μ„ long κ°’μœΌλ‘œ 리턴함
               val  timeFormat:SimpleDateFormat =  SimpleDateFormat("yyyy-mm-dd hh:mm:ss")
               val str = timeFormat.format(Date(curTime))
               println(str)
               println(Date(curTime))
               println()
               delay(500L) // μ·¨μ†Œμ— ν˜‘μ‘°μ μœΌλ‘œ κ΅¬ν˜„μ΄ λ˜μ–΄μžˆμŒ
           }
       }finally {
           // λ¦¬μ†ŒμŠ€ ν•΄μ œ 지역
           println("job: i'm runnig finally")
       }
    }

    delay(1300L)
    println("main : Tired waiting")
    job.cancelAndJoin() // μΌμ‹œ 쀑단 λ˜μ—ˆλ‹€κ°€ 재개 될 λ•Œ, exception을 던질 λ•Œ finally λΈ”λ‘μ—μ„œ λ¦¬μ†ŒμŠ€ ν•΄μ œλ₯Ό 해라.
    println("main : Now I can quit")
}

 

Timeout

// Timeout
// 코루틴이 μ‹œμž‘λ  λ•Œ, 이 μ‹œκ°„μ΄ μ§€λ‚˜λ©΄ 이 코루틴은 μ·¨μ†Œ λœλ‹€. 미리 νƒ€μž„ 아웃을 μ§€μ •ν•˜λŠ” 방식
// withTimeout을 μ“°λ©΄ TimeoutCancellationException 이 λ‚˜λŠ”λ°,
// withTimeoutOrNull 이면 Exception났을 λ•Œ, κ²°κ³Ό 값이 null둜 떨어짐.

fun main() = runBlocking {
    val result = withTimeoutOrNull(2000L){
        repeat(1000){
            i -> println("i'm sleeping ${i}..")
            delay(500L)
        }
        "Done"
    }
    println("Result is ${result}")
}
λ°˜μ‘ν˜•