티스토리 뷰
728x90
4. 비동기 흐름 제어: suspend
함수와 withContext
4.1 suspend
함수란?
suspend
는 코틀린에서 비동기 작업을 정의할 때 사용되는 키워드입니다. suspend
함수는 일시 중단될 수 있는 함수로, 실행 중간에 일시적으로 멈췄다가 다른 작업을 처리한 후 다시 재개될 수 있습니다. 일반 함수와는 달리 코루틴 내에서만 호출될 수 있으며, 비동기 작업을 처리하는 데 최적화되어 있습니다.
suspend
함수는 동기적 코드처럼 작성하지만, 실제로는 비동기적으로 실행되어 코드 가독성을 크게 향상시킵니다.
suspend
함수의 특징:
- 코루틴 내에서만 호출될 수 있습니다.
- 코루틴 내에서 호출된
suspend
함수는 일시적으로 중단되었다가 재개될 수 있습니다. - 비동기 흐름 제어를 동기적 코드처럼 간단하고 직관적으로 작성할 수 있습니다.
suspend
함수의 기본 사용 예제
import kotlinx.coroutines.*
// suspend 키워드를 사용해 비동기 함수를 정의
suspend fun performTask() {
delay(1000L) // 비동기 지연
println("Task completed")
}
fun main() = runBlocking {
performTask() // suspend 함수는 코루틴 내에서만 호출 가능
println("Main program ends")
}
설명:
performTask
함수는suspend
키워드를 사용하여 비동기 작업을 정의했습니다.- 이 함수는 코루틴 내에서만 호출 가능하므로,
runBlocking
내부에서 호출하여 비동기 작업을 수행합니다. delay
는 코루틴을 일시적으로 중단시킨 후 1초 뒤에 재개됩니다.
출력:
Task completed
Main program ends
4.2 withContext
란?
withContext
는 다른 디스패처(Dispatcher)로 컨텍스트를 변경하면서 특정 블록의 코드를 실행하는 코루틴 빌더입니다. 이를 통해, 입출력 작업(I/O)이나 CPU 집약적인 작업을 다른 디스패처에서 처리하고, 메인 스레드의 부하를 줄일 수 있습니다.
withContext
의 특징:
- 코루틴의 컨텍스트를 변경하여 특정 블록의 코드를 다른 디스패처에서 실행할 수 있습니다.
- 주로 입출력 작업(Dispatchers.IO), CPU 집중 작업(Dispatchers.Default), UI 작업(Dispatchers.Main)을 구분할 때 사용됩니다.
- 코드를 일시 중단한 후, 다른 컨텍스트에서 재개할 수 있습니다.
withContext
예제
import kotlinx.coroutines.*
fun main() = runBlocking {
println("Main program starts: ${Thread.currentThread().name}")
// withContext를 사용해 디스패처를 변경
val result = withContext(Dispatchers.IO) {
println("Performing I/O operation on: ${Thread.currentThread().name}")
delay(1000L) // I/O 작업을 시뮬레이션
"Result of I/O operation"
}
println("Received result: $result")
println("Main program ends: ${Thread.currentThread().name}")
}
설명:
withContext
는 코드 블록을Dispatchers.IO
에서 실행하도록 하여, 입출력 작업을 별도의 스레드에서 처리할 수 있습니다.- 코드 블록이 완료되면 결과값을 반환하고, 원래의 컨텍스트로 돌아가서 나머지 코드를 실행합니다.
- 이 코드는 메인 스레드에서 시작하지만, 입출력 작업은 별도의 I/O 스레드에서 처리됩니다.
출력:
Main program starts: main
Performing I/O operation on: DefaultDispatcher-worker-1
Received result: Result of I/O operation
Main program ends: main
- 메인 프로그램은 메인 스레드에서 시작하지만, 입출력 작업은
Dispatchers.IO
에서 수행되며, 별도의 스레드(DefaultDispatcher-worker-1)에서 실행됩니다. - 입출력 작업이 완료된 후, 결과값을 받아 메인 스레드에서 출력됩니다.
4.3 suspend
함수와 withContext
결합
suspend
함수와 withContext
를 결합하여 효율적인 비동기 작업을 처리할 수 있습니다. 입출력 작업이나 네트워크 작업을 별도의 스레드에서 처리하고, 그 작업이 끝나면 메인 스레드로 돌아와서 UI를 업데이트하는 방식으로 사용됩니다.
예제: suspend
와 withContext
결합
import kotlinx.coroutines.*
// suspend 함수로 네트워크 작업 시뮬레이션
suspend fun fetchData(): String {
return withContext(Dispatchers.IO) { // I/O 스레드에서 실행
println("Fetching data on: ${Thread.currentThread().name}")
delay(1000L) // 네트워크 지연 시뮬레이션
"Data from server"
}
}
fun main() = runBlocking {
println("Main program starts: ${Thread.currentThread().name}")
// suspend 함수 호출
val data = fetchData()
println("Received data: $data")
println("Main program ends: ${Thread.currentThread().name}")
}
설명:
fetchData
함수는 네트워크 작업을 비동기적으로 시뮬레이션하며, 이 작업은Dispatchers.IO
에서 실행됩니다.fetchData
함수가 완료되면 데이터가 반환되고, 메인 스레드에서 결과를 처리할 수 있습니다.
출력:
Main program starts: main
Fetching data on: DefaultDispatcher-worker-1
Received data: Data from server
Main program ends: main
- 입출력 작업은 별도의 I/O 스레드에서 실행되고, 네트워크 작업이 완료된 후 메인 스레드로 돌아와 데이터를 처리합니다.
4.4 withContext
의 주요 활용 사례
withContext
는 주로 입출력 작업이나 CPU 집약적인 작업을 별도의 스레드에서 처리하고, 그 후에 메인 스레드로 돌아와 결과를 처리할 때 유용합니다.
- 네트워크 작업 처리:
- 네트워크 요청이나 파일 입출력과 같은 작업은
Dispatchers.IO
에서 처리하여, 메인 스레드의 부하를 줄입니다.
- 네트워크 요청이나 파일 입출력과 같은 작업은
- CPU 집약적 작업 처리:
- 데이터 처리나 계산 작업과 같은 CPU 집약적 작업은
Dispatchers.Default
에서 처리하여, 다른 작업에 영향을 주지 않도록 합니다.
- 데이터 처리나 계산 작업과 같은 CPU 집약적 작업은
- UI 업데이트:
- 안드로이드나 UI 환경에서는
Dispatchers.Main
을 사용하여 UI 업데이트 작업을 메인 스레드에서 수행합니다.
- 안드로이드나 UI 환경에서는
4.5 suspend
와 withContext
를 활용한 실제 프로젝트 구성
다음은 간단한 네트워크 요청 시뮬레이션을 통해 suspend
함수와 withContext
를 활용하여 비동기적으로 데이터를 처리하는 방식입니다.
예제: 네트워크 데이터 처리 시뮬레이션
import kotlinx.coroutines.*
// suspend 함수로 데이터를 가져오는 함수
suspend fun fetchDataFromNetwork(): String {
return withContext(Dispatchers.IO) {
println("Fetching data on: ${Thread.currentThread().name}")
delay(2000L) // 네트워크 지연 시뮬레이션
"Data from network"
}
}
// suspend 함수로 데이터를 처리하는 함수
suspend fun processData(data: String) {
withContext(Dispatchers.Default) {
println("Processing data on: ${Thread.currentThread().name}")
delay(1000L) // 데이터 처리 시뮬레이션
println("Data processed: $data")
}
}
fun main() = runBlocking {
println("Main program starts: ${Thread.currentThread().name}")
// 네트워크에서 데이터를 가져오고 처리
val data = fetchDataFromNetwork
()
processData(data)
println("Main program ends: ${Thread.currentThread().name}")
}
설명:
fetchDataFromNetwork
함수는 네트워크에서 데이터를 가져오는 작업을 시뮬레이션하며, 입출력 작업은Dispatchers.IO
에서 처리됩니다.processData
함수는 데이터를 처리하는 작업을 CPU 집약적인 작업으로 시뮬레이션하며,Dispatchers.Default
에서 처리됩니다.- 두 함수는 모두 비동기적으로 실행되며,
withContext
를 통해 스레드 간의 작업 분배가 이루어집니다.
출력:
Main program starts: main
Fetching data on: DefaultDispatcher-worker-1
Processing data on: DefaultDispatcher-worker-2
Data processed: Data from network
Main program ends: main
- 네트워크 작업은 I/O 스레드에서 실행되고, 데이터 처리 작업은 CPU 스레드에서 실행됩니다. 작업이 완료된 후 메인 스레드로 돌아와 프로그램이 종료됩니다.
요약
suspend
함수는 코루틴에서 비동기 작업을 정의하는 함수입니다. 이 함수는 중단될 수 있으며, 코루틴 내에서만 호출할 수 있습니다.withContext
는 코루틴의 컨텍스트를 다른 디스패처로 변경하여, 입출력 작업이나 CPU 집약적인 작업을 별도의 스레드에서 처리하고, 메인 스레드의 부하를 줄일 수 있습니다.suspend
함수와withContext
의 결합은 복잡한 비동기 작업을 동기적 흐름처럼 간결하게 처리할 수 있게 해주며, 스레드 자원의 효율적인 사용을 가능하게 합니다.
728x90
'개발 언어 > 코틀린' 카테고리의 다른 글
kotlin - coroutine (6) 코루틴 취소 및 타임아웃 (0) | 2024.09.05 |
---|---|
kotlin - coroutine (5) 코루틴 채널(Channels) 및 흐름(Flow) (2) | 2024.09.05 |
kotlin - coroutine (3) 코루틴의 동작 원리 및 구조화된 동시성 (Structured Concurrency) (0) | 2024.09.05 |
kotlin - coroutine (1) 코루틴의 기초 개념 (0) | 2024.09.05 |
코틀린 고급편 - 어노테이션 & 리플렉션 활용 (0) | 2024.07.18 |
댓글