suspend
가 붙은 함수는 다른 suspend
가 붙은 함수를 호출할 수 있다. (가장 기본 개념)suspend
함수가 없는데 어떻게 suspend fun delay
를 호출했는가?fun main(): Unit = runBlocking {
launch {
delay(100L) // <- 이거 suspend fun 인데, 어케 호출?
}
}
launch
가 가지고 있는 마지막 파라미터 block이 suspend
lambda 였기 때문에 가능함public fun CoroutineScope.launch(
//...
block: suspend CoroutineScope.() -> Unit // 어려운말로 suspending lambda
): Job {
// ...
}
launch
와runBlocking
의block
파라미터는 모두suspend
lambda입니다. 따라서 이 블록 내부에서는 다른suspend
함수를 호출할 수 있습니다.
suspend fun
: 코루틴이 중지되었다가 재개 될 수 있는 지점 (suspension point)
fun main(): Unit {
var result1 = call1()
var result2 = call2(result1);
}
suspend fun call1(): Int {
return CoroutineScope(Deispatchers.Default).async {
Thread.sleep(1000L)
}.await()
}
suspend fun call2(num: Int): Int {
return CompletableFuture.supplyAsync {
Thread.sleep(1000L)
num * 2
}.await()
}
call2
에서는 코루틴 제공 함수가 아닌 CompletableFuture
비동기 함수를 사용했지만CompletableFuture
상위 인터페이스에 미리 await()
를 확장 함수로 정의해둠참고:
CompletableFuture
의await()
확장 함수는kotlinx.coroutines.future
패키지에 포함되어 있습니다. 이를 사용하려면 해당 패키지를 import 해야 합니다.
// coroutineScope 로 새로운 코루틴을 만듬
suspend fun calculateResult(): Int = coroutineScope {
// num1 자식 코루틴 생성
val num1 = async {
delay(1000L)
10
}
// num2 자식 코루틴 생성
val num2 = async {
delay(1000L)
20
}
num1.await() + num2.await();
}
fun main(): Unit = runBlocking {
println("START")
println(calculateResult()) // coroutineScope 로 만들어진 코루틴은 즉시 실행됨
println("END")
// 결과 START -> 30 -> END
}
coroutineScope
는 또 다른 코루틴들을 동시에 여러개 사용하고 싶은데, 그러한 기능을 또 다른 함수로 분리하고 싶을 때 사용된다. (새로운 작업 단위를 만들고 해당 작업이 완료될 때까지 기다리는 구조를 의미함)참고:
coroutineScope
는 여러 자식 코루틴을 동시에 실행하고, 이들이 모두 완료될 때까지 기다리는 구조적 동시성(concurrent)을 관리하는 데 사용됩니다. 이를 통해 특정 기능을 수행하는 코드를 별도의 함수로 분리하여 가독성을 높이고, 자식 코루틴의 생명주기를 일관되게 관리할 수 있습니다.
coroutineScope
와 기본적으로 유사함suspend fun calculateResult(): Int = withContext(Dispatchers.Default) {
// num1 자식 코루틴 생성
val num1 = async {
delay(1000L)
10
}
// num2 자식 코루틴 생성
val num2 = async {
delay(1000L)
20
}
num1.await() + num2.await();
}
참고:
withContext
는 지정된 컨텍스트로 코루틴을 전환하고, 해당 컨텍스트에서 코드를 실행합니다. 이는 주로 특정 디스패처에서 코드를 실행하거나, 컨텍스트 전환이 필요한 경우에 사용됩니다.
coroutineScope
와 기본적으로 유사함withTimeout
은 주어진 시간 동안 완료되지 못하면 Exception
발생withTimeoutOrNull
은 주어진 시간 동안 완료되지 못하면 null
반환// withTimeout
fun main(): Unit = runBlocking {
var result: Int = withTimeout(1000L) {
delay(1500L)
10_20
}
println(result) // throw TimeoutCancellationException
}
// withTimeoutOrNull
fun main(): Unit = runBlocking {
var result: Int? = withTimeout(1000L) {
delay(1500L)
10_20
}
println(result) // null
}
coroutineScope
는 새로운 코루틴 스코프를 생성하여 모든 자식 코루틴이 완료될 때까지 기다리지만, withContext
는 현재 코루틴 컨텍스트를 변경하여 실행하는 차이점이 있습니다. withContext
는 특정 컨텍스트로 코드를 실행하고자 할 때 사용합니다.
withContext
는 컨텍스트 전환이 필요한 특정 작업에 유용하며, 예를 들어, I/O 작업을Dispatchers.IO
로 실행하거나, CPU 바운드 작업을Dispatchers.Default
로 실행할 때 사용됩니다.
- suspend 함수의 사용 범위:
suspend
함수는 코루틴 내에서 호출되며, 이는 비동기 작업을 동기 코드처럼 작성할 수 있게 해줍니다.suspend
함수는 실행 도중 일시 중단될 수 있으며, 다른suspend
함수와 함께 사용되어 복잡한 비동기 로직을 간결하게 표현할 수 있습니다.- coroutineScope와 supervisorScope의 차이:
coroutineScope
는 자식 코루틴 중 하나라도 실패하면 부모 코루틴이 취소되지만,supervisorScope
는 자식 코루틴의 실패가 다른 자식이나 부모 코루틴에 영향을 미치지 않습니다.