[Kotlin] Coroutines 3

sundays·2022년 11월 28일
0

kotlin

목록 보기
13/19

완료를 기다리기 위한 블로킹

runBlocking의 사용

  • 새로운 코루틴을 실행하고 완료되기 전까지는 현재(caller) 스레드를 블로킹
  • 코루틴 빌더와 마찬가지로 CoroutineScope의 인스턴스를 가짐
fun <T> runBlocking(
	context: CoroutineContext = EmptyCoroutineContext,
    block: suspend CoroutineScope.() -> T
) : T (source)

1. main 스레드 자체를 잡아두기 위해

fun main() = runBlocking<Unit> { // 메인 메서드가 코루틴 환경에서 실행
    launch { // 백 그라운드로 코루틴 실행
        delay(1000L)
        println("world")
    }
    println("Hello") // 즉시 이어서 실행됨
    // delay(2000L) // delay() 를 사용하지 않아도 코루틴을 기다림
}

2. runblock()을 클래스 멤버 메서드에서 사용할때

class Mytest {
	fun mysuspendMethod() = runBlocking<Unit> {
		.. 
    }
}

3. 특정 디스패처 옵션을 줄때

runBlocking(Dispatchers.IO) {
	launch {
    	repeat(5) {
        	println("counting ${it + 1}")
            delay(1000)
        }
	}
}

특정 문맥과 함께 실행

withContext()

  • 인자로 코루틴 문맥을 지정하며 해당 문맥에 따라 코드 블록을 실행
  • 해당 코드 블록은 다른 스레드에서 수행되며 결과를 반환한다
  • 부모 스레드는 블록하지않는다
// 함수 원형
suspend fun <T> withContext(
	context: CoroutineContext,
    block:suspend CoroutineScope.() -> T
) : T (source)

// 사용 예시
resultTwo = withContext(Dispatchers.IO) { function2() }

또 다른 사용 예

완료 보장

  • withContext(NonCancellable) { ... }
    • catch { .. } finally { ... } 에서 finally 블록의 실행을 보장하기 위해 취소 불가 블록 구성

Scope Builder

coroutineScope Builder

suspend fun <R> coroutineScope(
	block:suspend CoroutineScope.() -> R
): R (source)
  • 자신만의 코루틴 스코프 를 선언하고 생성할 수 있다. (구조화된 코루틴)
  • 모든 자식이 완료되기 전까진 생성된 코루틴 스코프는 종료되지 않는다
  • runblocking과 유사하지만 runblocking은 단순 함수로 현재 스레드를 블로킹
    coroutineScope은 단순히 지연(suspend) 함수 형태로 넌블로킹으로 사용
  • 만일 자식 코루틴이 실패하면 이 스코프도 실패하고 남은 자식은 모두 취소된다. 반면에 supervisorscope는 실패하지 않음
    • 외부에 의해 작업이 취소되는 경우 cancellatonException 발생

supervisorScope Builder

fun SupervisorJob(parent:Job? = null) : CompletableJob (source)
  • 코루틴 스코프를 생성하며 supervisorjob과 함께 생성하여 기존 문맥의 job을 Override 한다
    • launch 를 사용해 생성한 작업의 실패는 coroutineExceptionHandler를 통해 핸들링
    • async 를 사용해 생성한 작업의 실패는 deffered.await 의 결과에 따라 핸들링
    • parent 를 통해 부모 작업이 지정되면, 자식작업이 되며 부모에 따라 취소 여부 결정
  • 자식이 실패하더라도 이 스코프는 영향을 받지 않으므로 실패하지 않는다
    • 실패를 핸들링하는 정책을 구현할 수 있다.
  • 예외나 의도적인 취소에 의해 이 스코프의 자식들을 취소하지만 부모의 작업은 취소하지 않는다.

병렬 분해

suspend fun loadandcombined(name1:String, name2:String) : Image {
	val defered1 = async { loadImage(name1) } // 네트워크 불안정등으로 취소 될 경우
    val defered2 = async { loadImage(name2) }
    return combineImages(defered1.await(), defered2.await())
}
  • loadImage(name2) 는 여전히 진행된다
  • 코루틴 문맥에서 실행하여 자식 코루틴으로 구성한다면 예외를 부모에 전달하고 모든 자식 코루틴을 취소할 수 있다
// 스코프를 주어줌으로서 특정 자식 코루틴이 취소가 생기면 모든자식을 취소하게 됨
suspend fun loadAndCombined(name1:String, name2: String): Image = CoroutineScope { 
	val defered1 = async { loadImage(name1) }
    val defered2= async { loadImage(name2) }
    combineImage(deferred1.await(), deferred2.await())
}

스코프 취소와 예외처리

  • 스코프 취소
val scope2 = CoroutineScope
val routine1 = scope2.launch { ... }
val routine2 = scope2.async { ... }

/** 취소 **/
// scope2.cancel()
또는
// scope2.cancelChildren()

try {
	...
} catch (e: CancellationExcpetion) {
	.. 취소 예외 처리
}

코루틴의 실행 시간 지정

실행 시간 제한

  • withTimeout(시간값) { ... }
    • 특정 시간값 동안만 수행하고 블록을 끝냄
    • 시간값이 되면 timeCancellationException 예외를 발생
  • withTimeoutOrNull(시간값) { ... }
    • 동작은 위와 동일
    • 단 예외를 발생하지 않고 null을 반환
val result = withTimeOrNull(1300L) {
	repeat(1000) { i ->
    	println("I'm sleeping $i ...")
        delay(500L)
    }
    "DONE" // 코루틴 블록이 취소 되면 이 값이 result에 반환
}
printn("Result is $result")

Reference

  • 코틀린 프로그래밍 - 황영덕
profile
develop life

0개의 댓글