파이썬이나 자바스크립트 같은 언어에서는 아래와 같이 제한된 형태의 코루틴을 사용하고 있다.
1) 비동기 함수 (async/await)
2) 제너레이터 함수 (값을 순차적으로 반환)
코틀린에서는 제너레이터 대신 시퀀스를 생성할 때 사용하는 시퀀스 빌더를 제공한다.
코틀린의 시퀀스는 List나 Set 같은 컬렉션과 비슷한 개념인데, 필요할 때마다 값을 하나씩 계산하는 지연 처리를 한다.
시퀀스의 특징
- 요구되는 연산을 최소한으로 수행
- 무한정이 될 수 있음
- 메모리 사용이 효율적
-> Q: 무한정. 메모리 효율?
시퀀스는 sequence라는 함수를 이용해 정의된다.
시퀀스의 람다 표현식 내부에서는 yield 함수를 호출하여 다음 값을 생겅한다.
val seq = sequence {
yield(1)
yield(2)
yield(3)
}
fun main() {
for(num in seq) {
print(num)
} // 123
}
시퀀스의 작동 방식: 중단이 가능하여, 사용되는 함수와 시퀀스 제너레이터가 번갈아가면서 실행되는 방식
[실제 사용 예제]
- 데이터베이스에서 대량의 데이터를 처리하거나, 원격 브라우저에서 수집한 데이터를 스트리밍 방식으로 처리
fun processLargeDataSet(): Sequence<ProcessedData> = sequence {
// 데이터 소스에서 청크 단위로 데이터 가져오기
var chunk = dataRepository.getNextChunk(chunkSize)
while (chunk.isNotEmpty()) {
// 각 아이템 처리 및 yield
for (item in chunk) {
val processedItem = processItem(item)
yield(processedItem)
}
// 다음 청크 가져오기
chunk = dataRepository.getNextChunk(chunkSize)
}
}
// 사용 예
processLargeDataSet()
.filter { it.isValid }
.map { it.transform() }
.take(100)
.forEach { kafkaProducer.send(it) }
대량의 데이터 및 실시간 처리에 적합한데, 메모리 효율성이 높은 이유?
필요한 시점에만 계산 (Lazy Evaluation)
- 전체 데이터셋을 한 번에 메모리에 로드하지 않고, 필요한 부분만 로드
- 예시: 1백만 개의 레코드가 있을 때 List를 사용하면 모든 레코드를 메모리에 로드해야 하지만,
Sequence를 사용하면 처리 중인 청크만 메모리에 유지
스트림 처리 방식
- 데이터를 청크 단위로 처리하므로 메모리 사용량이 청크 크기에 비례
- 예: 1GB 데이터를 10MB 청크로 나누어 처리하면 한 번에 10MB만 메모리에 로드
중간 컬렉션 생성 방지
- filter, map 등의 연산이 즉시 실행되지 않고 최종 연산(forEach, toList 등)이 호출될 때까지 지연
- 이로 인해 중간 결과를 저장하는 임시 컬렉션이 생성되지 않음
단일 패스 처리
- 시퀀스는 모든 연산을 요소별로 한 번에 처리
- List를 사용: list.filter {...}.map {...} 는 두 개의 별도 리스트를 생성
- Sequence 사용: sequence.filter {...}.map {...} 는 각 요소에 대해 filter와 map을 순차적으로 적용하여 추가 컬렉션을 만들지 않음
'Study OR Book > Book' 카테고리의 다른 글
[코틀린 코루틴] 1장 코틀린 코루틴을 배워야 하는 이유 (0) | 2025.05.20 |
---|---|
[실전 레디스] Chaprter 01_레디스의 시작 (0) | 2025.05.20 |
[이펙티브 코틀린] 아이템46: 함수 타입 파라미터를 갖는 함수에 inline 한정자를 붙여라 (0) | 2025.02.20 |
[이펙티브 코틀린] 아이템43: API의 필수적이지 않는 부분을 확장 함수로 추출하라 (0) | 2025.02.18 |
[이펙티브 코틀린] 아이템40: equals의 규약을 지켜라 (0) | 2025.02.10 |