이번 글에서는 eager evaluation과 lazy evaluation에 대해 알아보겠습니다.

이 글은 Kotlin 1.9.0을 기준으로 작성하였으며 참고 자료는 다음과 같습니다.

Eager evaluation

Eager evaluation은 변수나 함수가 호출될 때 바로 계산하는 처리 방식입니다.

장점

  • 값을 바로 계산하기 때문에 코드의 흐름을 파악하기 쉽다.
  • 어느 지점에서 오류가 발생했는지 디버깅하기 쉽다.
  • 값을 계산할지 판단하는 overhead가 발생하지 않는다.

단점

  • 작업에서 불필요한 데이터도 계산하여 자원 낭비가 발생한다.
  • 무한 개의 데이터를 처리할 수 없다.

Lazy evaluation

Lazy evaluation은 값이 필요할 때까지 계산을 지연하는 처리 방식입니다. 장단점은 다음과 같습니다.

장점

  • 불필요한 계산을 피할 수 있어 CPU와 메모리 자원을 아낄 수 있다.
  • 값이 필요한 시점까지만 계산하므로 큰 데이터를 다룰 때 용이하고 무한개의 데이터도 다룰 수 있다.

단점

  • 값이 필요할 때 계산되므로 디버깅에 어려움을 겪을 수 있다.
  • 값이 필요한지 확인하는 과정에서 발생하는 overhead로 인해 작은 데이터를 다룰 때 느릴 수 있다.

Kotlin에서 확인하기

Kotlin의 Collection과 Sequence를 이용하면 두 방식의 처리 방법을 쉽게 확인할 수 있는데요. 각 자료형의 동작 방식은 다음과 같습니다.

  • Collection: eager evaluation
  • Sequence: lazy evaluation

그럼 1부터 10까지 정수 리스트가 주어질 때 짝수 3개 리스트를 구하는 코드를 보겠습니다.

internal class EvaluationTest : BehaviorSpec({
    given("1부터 10까지 정수 리스트가 주어진다.") {
        val nums = (1..10).toList()

        `when`("Collection을 이용하여 짝수 3개를 필터링하면") {
            val result = nums
                .filter { println("filter target = $it"); it % 2 == 0 }
                .onEach { println("filtered = $it") }
                .take(3)

            then("Eager evaluation으로 처리한다.") {
                result shouldBe listOf(2, 4, 6)
            }
        }

        `when`("Sequence를 이용하여 짝수 3개를 필터링하면") {
            val result = nums.asSequence()
                .filter { println("filter target = $it"); it % 2 == 0 }
                .onEach { println("filtered = $it") }
                .take(3)
                .toList()

            then("Lazy evaluation으로 처리한다.") {
                result shouldBe listOf(2, 4, 6)
            }
        }
    }
})

Collection의 경우

Eager evaluation으로 처리하는 Collection의 경우 각 단계에서 모든 값을 계산한 후 다음 단계로 넘어갑니다.

Untitled.png

  • 첫 번째 단계에서 계산한 값: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
  • 두 번째 단계에서 계산한 값: 2, 4, 6, 8, 10
  • 전체 개수: 15개

Untitled.png

Sequence의 경우

Lazy evaluation으로 처리하는 Sequence의 경우 하나의 원소가 모든 단계를 거친 후 다음 원소를 처리합니다.

Untitled.png

  • 첫 번째 단계에서 계산한 값: 1, 2, 3, 4, 5, 6
  • 두 번째 단계에서 계산한 값: 2, 4, 6
  • 전체 개수: 9개

Untitled.png

결과

똑같은 결과를 얻는데 있어 lazy evaluation이 eager evaluation보다 40% 효율적입니다.

마무리하며

이번 글에서는 eager evaluation과 lazy evaluation에 대해 알아보았습니다. Kotlin의 Collection과 Sequence를 이용하여 lazy evaluation의 효율을 두 눈으로 확인할 수 있었는데요. lazy evaluation는 처리해야하는 데이터가 크면 클수록 더 높은 효율을 보일 것입니다.

개인적으로 eager evaluation과 lazy evaluation을 이해하기 정말 어려웠는데요. 다행히 Kotlin의 Sequence의 존재를 알고 테스트 코드를 작성하니 쉽게 이해할 수 있었습니다. 아무래도 저는 학습 테스트로 공부하는게 가장 빨리 배우는 것 같네요. 😭

이번 글에서 사용한 코드는 이 곳에서 확인하실 수 있습니다.

카테고리:

업데이트:

댓글남기기