본문 바로가기
개발 서적

[코틀린 코루틴의 정석] 9. 일시 중단 함수

by liz_devel 2025. 12. 31.

9장 일시 중단 함수를 읽고 간단하게 정리한 글이다.

 


 

일시 중단 함수란?

suspend fun 키워드로 선언되는 함수로 함수 내에 일시 중단 지점(suspend point)을 포함하고 있다.

일시 중단 함수는 주로 코루틴의 비동기 작업과 관련된 복잡한 코드들을 구조화하고 재사용할 수 있는 코드의 집합으로 만드는 데 사용한다.

 

 

일시 중단 함수는 코루틴인가?

아니다.

많이 하는 실수 중 하나는 일시 중단 함수를 코루틴과 동일하게 생각하는 것이다.

일시 중단 함수는 코루틴 내부에서 실행되는 코드의 집합일 뿐, 코루틴이 아니다.

 

만약, 일시 중단 함수를 코루틴처럼 사용하고 싶다면 일시 중단 함수를 코루틴 빌더로 감싸야 한다.

 

코루틴 빌더에는 launch, async 등이 있다.

 

 

일시 중단 함수의 호출 가능 지점

일시 중단 함수는 일시 중단을 할 수 있는 곳에서만 호출할 수 있다.

 

1. 코루틴 내부

2. 일시 중단 함수

 

코루틴 내부에서 일시 중단 함수 호출하기

fun main() = runBlocking<Unit> {
 delayAndPrint (keyword = "I'm Parent Coroutine")
 launch{
 	delayAndPrint(keyword = "I'm Chile Coroutine")
   }
 }
 
 suspend fun delayAndPrint(keyword: String) {
  delay(1000L)
  println(keyword)
  }
  
  /*
  //결과:
  I'm Parent Coroutine
  I'm Chile Coroutine
  */

 

코드의 실행 결과를 보면 각 코루틴이 일시 중단 함수를 정상적으로 실행한 것을 확인할 수 있다. 이처럼 일시 중단 함수는 코루틴에서 호출될 수 있다.

 

 

일시 중단 함수에서 다른 일시 중단 함수 호출하기

일시 중단 함수 내부에서 일시 중단 함수를 호출할 수 있다.

suspend fun searchByKeyword(keyword: String): Array<String> {
 val dbResults = searchFromDB(keyword)
 val serverResults = searchFromServer(keyword)
 	return arrayOf(dbResult, serverResult)
 }
 
 suspend fun searchFromDB(keyword: String): Array<String> {
  delay(1000L)
  return arrayOf("[DB]${keyword}1", "[DB]${keyword}2")
}
  
  suspend fun searchFromServer(keyword: String): Array<String> {
   delay(1000L)
   return arrayOf("[Server]${keyword}1", "[Server]${keyworkd}2")
 }

 

 

일시 중단 함수에서 코루틴 실행하기

일시 중단 함수에서 launch나 async 같은 코루틴 빌더 함수를 호출하기 위해서는 일시 중단 함수 내부에서 CoroutineScope 객체에 접근할 수 있도록 해야 한다.( launch나 async 같은 코루틴 빌더 함수는 CoroutineScope의 확장 함수로 선언돼 있기 때문에)

-> coroutineScope 함수를 사용해 만든 CoroutineScope 객체를 사용해 launchasync 같은 코루틴 빌더를 호출할 수 있다. 이를 사용하면 일시 중단 함수 내부에서 비동기 작업을 병렬로 실행할 수 있다.

suspend fun searchByKeyword(keyword: String): Array<String> = coroutineScope
{ // this: CoroutineScope
   val dbResultDeferred = async {
     searchFromDB(keyword)
   }
   val serverResultDeferred = async {
     searchFromServer(keyword)
   }
   
   return@coroutineScope arrayOf(dbResultDeferred.await(), serverResultDeferred.await())
 }

 

 

 

위 코드들로 단위 테스트 해보았을 때 결과(async 코루틴 빌더를 사용하고 안 하고에 따라 처리 시간이 차이 나는 것을 볼 수 있다)

package com.example.couroutine_test

import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
import org.junit.Test
import kotlin.system.measureTimeMillis

class SearchCoroutineRealTimeTest {

    @Test
    fun `순차 vs 병렬 실제 시간 비교`() = runBlocking {
        val sequentialTime = measureTimeMillis {
            searchSequential("test")
        }

        val parallelTime = measureTimeMillis {
            searchParallel("test")
        }

        println("순차 실행 시간: $sequentialTime ms")
        println("병렬 실행 시간: $parallelTime ms")

        assert(sequentialTime >= 1900)
        assert(parallelTime in 900..1500)
    }
}


suspend fun searchSequential(keyword: String): Array<Array<String>> {
    val db = searchFromDB(keyword)
    val server = searchFromServer(keyword)
    return arrayOf(db, server)
}

suspend fun searchParallel(keyword: String): Array<Array<String>> =
    coroutineScope {
        val db = async { searchFromDB(keyword) }
        val server = async { searchFromServer(keyword) }
        arrayOf(db.await(), server.await())
    }

suspend fun searchFromDB(keyword: String): Array<String> {
    delay(1000L)
    return arrayOf("[DB]${keyword}1", "[DB]${keyword}2")
}

suspend fun searchFromServer(keyword: String): Array<String> {
    delay(1000L)
    return arrayOf("[Server]${keyword}1", "[Server]${keyword}2")
}

순차 실행 시간: 2018 ms
병렬 실행 시간: 1012 ms

 

CoroutineScope 함수 대신 suervisorScope 함수를 사용해 일시 중단 함수 내부에서 생성된 코루틴의 예외 전파를 제한할 수 있다.

 

반응형