기존에 다른 코루틴에 보내진 작업의 결과를 수신하려면 다음과 같이 코드를 만들어야 했다
suspend fun main() {
val deferred: Deferred<String> = CoroutineScope(Dispatchers.IO).async {
"Async Result"
}
val result = deferred.await()
println(result)
}
Deferred로 결과값을 감싼 다음 await() 메서드를 통해 해당 값이 수신될 때까지 기다려야 한다.
withContext를 이용한 비동기 작업 순차화
withContext를 이용하면 withContext의 두가지 특성 때문에 이러한 작업을 간단하게 만들 수 있다.
- withContext 블록의 마지막 줄의 값이 반환 값이 된다.
- withContext가 호출되면, 코루틴은 유지된체로 실행 환경(CoroutineContext)만 바꿔어 코루틴이 실행된다.
이러한 특성으로 인해 서로 다른 스레드에서 실행되야 하는 순차적인 작업이 필요한 경우에 withContext를 이용하면 된다. 직접 보는 것이 더욱 와닿으니 위의 코드를 한 번 수정해보자. 위의 Deferred와 await()을 이용한 코드는 아래와 같이 수정이 가능해진다.
suspend fun main() {
val result: String = withContext(Dispatchers.IO) {
"Async Result"// 반환 값
}
// result = "Async Result"
println(result)
}
위 코드는 다음과 같이 설명된다.
1. withContext 블록은 IO Thread의 작업이 끝나기 전까지 Main Thread에서 수행되는 코루틴을 일시중단되도록 만든다.
2. IO Thread의 작업이 끝나면 "Async Result"가 반환되며 이는 result에 세팅된다.
3. result가 프린트된다.
즉, 위의 Deferred 코드와 아래 코드는 동작은 물론 결과값 또한 같지만 코드의 양은 반이 되었다.
한계점
withContext는 launch 나 async와 달리 새로운 코루틴을 만드는 것이 아니라, 코루틴은 유지한체로 코루틴의 실행 환경만 바꿔서 실행한다. 따라서 둘 이상의 코루틴이 병렬로 실행돼야 할 경우에는 withContext를 사용하면 안된다. withContext를 사용해 순차적으로 처리하도록 만들어버리면 순차적으로 실행돼 비효율적이기 때문이다.
withContext를 이용하면 결과값 수신이 필요한 코드의 동기적 실행이 가능하다.
Kotlin Coroutines 공식 기술 문서 번역이 GitHub 오픈소스로 배포되었습니다. Starganizer가 되어 오픈소스를 지지해주세요.