완료를 기다리기 위한 블로킹
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")
}
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 { ... }
또는
try {
...
} catch (e: CancellationExcpetion) {
.. 취소 예외 처리
}
코루틴의 실행 시간 지정
실행 시간 제한
withTimeout(시간값) { ... }
- 특정 시간값 동안만 수행하고 블록을 끝냄
- 시간값이 되면 timeCancellationException 예외를 발생
withTimeoutOrNull(시간값) { ... }
- 동작은 위와 동일
- 단 예외를 발생하지 않고 null을 반환
val result = withTimeOrNull(1300L) {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
"DONE"
}
printn("Result is $result")
Reference