티스토리 뷰

반응형

Sequence

Sequence란 Kotlin에서 제공하는 기본 Collection으로 Java의 Stream에 대응되는 기능입니다.

Sequence는 Iterable과 같은 기능을 제공하고 있지만 복잡한 연산이나 많은 단계의 연산을 수행할때 좀 더 향상된 성능을 제공해줍니다.

 

Sequence vs Iterable 연산 처리 방식

  • Sequence는 하나의 요소마다 지정한 연산을 모두 적용
  • Iterable은 요소 전체에 지정한 연산을 모두 적용
  • Sequence는 연산에 대해 Lazy Evaluation(지연 계산)으로 처리하지만 Iterable은 Eager Evaluation(즉시 계산)으로 처리합니다.

 

Lazy Evaluation (지연 계산)

Lazy Evaluation(지연 계산) 이란 결과가 필요한 시점에만 연산을 수행하는 방식

Lazy Evaluation 방식을 사용하면서 얻을 수 있는 이점으로 연산중에 임시 컬렉션을 생성하지 않으면서 연산을 할 수 있다는 것입니다.

class Car(val name: String, val price: Int)

@Test
fun `lazy evaluation`() {
    val cars = listOf(
        Car("Seltos", 2600),
        Car("Sportage", 3300),
        Car("GV80", 6500),
        Car("X5", 12000),
        Car("GLE", 12000)
    )

    /* iterable 사용 */
    cars.map(Car::name)
        // [ "Seltos", "Sportage", "GV80", "X5", "GLE" ]

        .filter { it.startsWith("S") }
        // [ "Seltos", "Sportage" ]

    /* sequence 사용 */
    cars.asSequence()
        .map(Car::name)
        .filter { it.startsWith("S") }
        .toList()
        // [ "Seltos", "Sportage" ]
}

Iterable을 사용하는 경우 연산 단계별로 모든 요소에 대해 연산을 적용한뒤에 다음 단계로 넘어가기 때문에

cars 객체를 보면 map()함수 연산 결과에 대한 임시 컬렉션을 생성한 뒤에 filter() 함수 연산을 실행하게 됩니다.

 

그러나 sequence의 경우 임시 컬렉션을 생성하지 않고 각 요소마다 map(), filter() 함수 연산을 일괄적으로 실행합니다.

(sequence를 사용할려면 먼저 asSequence() 함수를 통해 collection타입을 sequence 타입으로 변경해야 한다.)

 

 

실제 연산 비교

val words = "The quick brown fox jumps over the lazy dog".split(" ")

/* iterable 사용 */
val lengthsList = words
    .filter{ it.length > 3 }
    .map{ it.length }
    .take(4)

/* sequence 사용 */
val lengthsSequence = words.asSequence()
    .filter { it.length > 3 }
    .map { it.length }
    .take(4)
    .toList()

 

iterable 사용하는 경우

  • 연산 단계별로 모든 요소에 연산을 적용

 

 

sequence 사용하는 경우

  • 각 요소마다 연산을 일괄 적용

 

이제 iterable과 sequence 연산의 차이점에 대해 알게되었고 sequence를 사용하는 경우 모든 요소에 연산을 적용하지 않기 때문에 성능에 이점이 있다는걸 이해했다.

하지만 모든 경우에 sequence가 iterable보다 성능이 좋은것은 아닌데요.

 

이걸 살펴보기 전에 한가지 이상한 점이 있습니다.

sequence를 사용하는 경우 연산을 다 마치고 마지막에 toList()를 통해 다시 Collection으로 변경해서 사용하게 됩니다.

 

왜 Sequence를 다시 Collection으로 돌려서 사용할까??

sequence를 그대로 사용해도 되는 경우는 한가지 경우 밖에 없습니다.

  • 원소를 차례대로 이터레이션 하는 경우

이러한 경우 외에는 index 통한 접근이나 collection의 다른 기능(추가, 삭제 등등)이 필요한 경우인데요.

sequence 타입은 해당 기능들을 지원하지 않기 때문에 collection으로 변환해서 사용해야 합니다.

 

 

Sequence 최적화

sequence가 기존 iterable 방식보다 연산의 효율성이 좋지만 모든 경우에 해당하는것은 아닙니다.

 

Sequence 사용시 주의사항

sequence는 사용하는 함수의 순서에 따라 성능 차이가 발생할 수 있습니다.

val cars = listOf(
    Car("Seltos", 2600),
    Car("Sportage", 3300),
    Car("GV80", 6500),
    Car("X5", 12000),
    Car("GLE", 12000)
)

/* map -> filter */
cars.asSequence()
    .map(Car::name)
    .filter { it.startsWith("S") }
    .toList()

/* filter -> map */
cars.asSequence()
    .filter { it.name.startsWith("S") }
    .map(Car::name)
    .toList()

 

map -> filter의 경우 모든 요소(Seltos, Sportage, GV80, X5, GLE)가 map(), filter() 함수 연산을 하게 됩니다.

  • 5 (모든 요소 갯수) X 2 (함수 연산 갯수) = 10
  • 총 10번의 연산을 수행

filter -> map의 경우 S로 시작하는 2개 원소(Seltos,Sportage)에만 map 함수 연산을 하게 됩니다.

  • 5 (filter는 모든 요소가 수행) + 2 (map은 filter를 통과한 요소만 수행) = 7
  • 총 7번의 연산을 수행

똑같은 연산이지만 map(), filter() 연산의 순서에 따라 연산을 수행하는 횟수가 달라지게 됩니다.

sequence 연산을 할때는 많은 부분을 필터링 할 수 있는 연산을 먼저 진행한다면 좀 더 큰 성능 차이를 낼 수 있습니다.

 

 

Sequence가 더 느린경우

Sequence가 기존 iterable 방식보다 더 느린경우도 존재합니다.

 

1. 원소의 갯수가 적거나 연산이 간단한 경우 sequence 연산이 더 느릴 수 있습니다.

출처: Kotlin 공식 문서

원소의 갯수가 적은 기준이랑 연산이 간단하다는 기준이 모호하게 느껴질 거라고 생각되는데요.

해당 부분에 대해서는 너무나 많은 경우들이 있고, 모든 경우를 아우르는 정확한 기준을 세울수가 없어서 사용하실 때 직접 sequence와 iterable 의 성능 차이를 비교해보는것이 가장 정확합니다.

 

 

2. sorted 함수 사용

sorted 함수를 처리할려면 내부적으로 임시 컬렉션을 생성해서 동작해야 합니다.

 

collection을 사용하는 경우 기존에도 임시 컬렉션을 사용하고 있으므로 바로 sorted 동작 수행이 가능하지만

 

sequence의 경우에는 원래 임시 컬렉션을 사용하지 않지만 sorted 연산을 하기 위해서 임시 컬렉션을 생성해 sorting을 한뒤 다시 sequence 형태로 변환을 해야해서 오히려 collection 보다 더 복잡한 동작을 수행하게 됩니다.

  • collection -> sequence (변환해서 연산시작) -> collection (sorted 연산을 위해 다시 변환) -> sequence (연산 마무리 후 다시 변환) -> collection (마지막에 toList()를 통해 변환)

 

마무리

Sequence를 사용할려면 여러 조건들을 고려해야 하지만 잘 사용한다면 성능향상에 도움이 되기 때문에 필요한 경우 적극도입해보시는걸 추천드립니다.

 

 

참고자료

https://kotlinlang.org/docs/sequences.html

 

Sequences | Kotlin

 

kotlinlang.org

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함