일시 중단 함수
1. suspend fun 키워드로 선언되고 함수 내에 일시 중단 지점을 포함하는 함수
2. 일시 중단 지점이 포함된 코드를 재사용이 가능한 단위로 추출
3. 코루틴 내부에서 실행되는 코드의 집합일 뿐 코루틴이 아니다
fun main() = runBlocking<Unit> {
delay(1000L)
println("Hello World")
delay(1000L)
println("Hello World")
}
// 결과
Hello World
Hello World
일시 중단 함수를 사용해 위 코드를 수정
suspend fun delayAndPrint() {
delay(1000L)
println("Hello World")
}
fun main() = runBlocking<Unit> {
val startTime = System.currentTimeMillis()
delayAndPrint()
delayAndPrint()
println(getElapsedTime(startTime))
}
// 결과
Hello World
Hello World
2.015 초
일시 중단 함수를 코루틴처럼 실행하기
코루틴 빌더 내부에 일시 중단 함수 사용
fun main() = runBlocking<Unit> {
val startTime = System.currentTimeMillis()
launch { delayAndPrint() }
launch { delayAndPrint() }
println(getElapsedTime(startTime))
}
// 결과
0.003초
Hello World
Hello World
suspend fun delayAndPrint() {
delay(1000L)
println("Hello World")
}
- 첫 번째 launch 빌더 내 delayAndPrint 실행 시 1초간 스레드 사용 권한 양보
- 두 번째 launch 빌더 내 delayAndPrint 실행 시 1초간 스레드 사용 권한 양보
- runBlocking 코루틴이 양보된 코루틴을 사용해 실행
- 약 1초 후 delayAndPrint print 출력
일시 중단 함수 사용하는 방법
호출 가능 지점 (코루틴 내부 / 일시 중단 함수)
코루틴 내부에서 호출
fun main() = runBlocking<Unit> {
delayAndPrint("Parent Coroutine")
launch {
delayAndPrint("Child Coroutine")
}
}
// 결과
1초 후 Parent Coroutine
1초 후 Child Coroutine
suspend fun delayAndPrint(message: String) {
delay(1000L)
println(message)
}
runBlocking, launch 빌더 모두 suspend 함수로 이루어져 있다
public actual fun <T> runBlocking(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T { ... }
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job { ... }
일시 중단 함수에서 호출
fun main() = runBlocking<Unit> {
val startTime = System.currentTimeMillis()
val result = searchByKeyword("Kancho")
println(result.joinToString(","))
println(getElapsedTime(startTime))
}
// 결과
[DB]Kancho1,[DB]Kancho2,[Server]Kancho1,[Server]Kancho2
2.035초
suspend fun searchByKeyword(keyword: String): Array<String> {
val dbResults = searchFromDB(keyword)
val serverResults = searchFromServer(keyword)
return arrayOf(*dbResults, *serverResults)
}
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")
}
문제점
2개의 일시 중단 함수가 하나의 코루틴에서 순차적 실행
다른 코루틴에서 실행되도록 하려면?
일시 중단 함수 내부에서 CoroutineScope 객체에 접근할 수 있어야 한다
일시 중단 함수에서 코루틴 실행하는 방법
coroutineScope 사용
단점
Child 코루틴에서 Exception이 발생하면 부모로 전파되어 전체 코루틴 취소
fun main() = runBlocking<Unit> {
val startTime = System.currentTimeMillis()
val results = searchByKeyword("Kancho")
println("[결과] ${results.toList()}")
println(getElapsedTime(startTime))
}
// 결과
[결과] [[DB]Kancho1, [DB]Kancho2, [Server]Kancho1, [Server]Kancho2]
1.022초
// 일시 중단 함수에서 coroutineScope 사용
// searchFromDB, searchFromServer 같이 실행
suspend fun searchByKeyword(keyword: String): Array<String> = coroutineScope {
val dbResults = async {
searchFromDB(keyword)
}
val serverResults = async {
searchFromServer(keyword)
}
return@coroutineScope arrayOf(*dbResults.await(), *serverResults.await())
}
supervisorScope 사용
구조화를 깨지 않고 예외 전파 방지
fun main() = runBlocking<Unit> {
val results = searchByKeyword("Kancho")
println("[결과] ${results.toList()}")
}
// 결과
dbResultsDeferred 예외 발생
[결과] [[Server]Kancho1, [Server]Kancho2]
suspend fun searchByKeyword(keyword: String): Array<String> = supervisorScope {
val dbResultsDeferred = async {
throw Exception("dbResultsDeferred 예외 발생")
searchFromDB(keyword)
}
val serverResultsDeferred = async {
searchFromServer(keyword)
}
val dbResults = try {
dbResultsDeferred.await()
} catch (e: Exception) {
println(e.message)
arrayOf()
}
val serverResults = try {
serverResultsDeferred.await()
} catch (e: Exception) {
arrayOf()
}
return@supervisorScope arrayOf(*dbResults, *serverResults)
}
'코루틴' 카테고리의 다른 글
[코루틴] 코루틴의 스레드 동작 (0) | 2024.09.21 |
---|---|
[코루틴] 코루틴(Coroutine)과 서브루틴(Subroutine) (0) | 2024.09.20 |
[코루틴] 예외 처리 (0) | 2024.09.16 |
[코루틴] 구조화된 동시성 (0) | 2024.09.08 |
[코루틴] CoroutineContext (0) | 2024.08.31 |