[Swift] Equatable vs Hashable 비교 성능 테스트

10812 단어 iOS실험실swiftiOS

먼저 Equatable , Comparable, Hashable 에 대해 초 간단히 알아봅시다.

Equatable: '==' 으로 비교 가능하게 해주는 녀석
Comparable: '<, >, <=, >=' 으로 비교 가능하게 해주는 녀석
Hashable: 해시값 만들어주는 녀석 ('1087909095493923794' 이런식)

그래서 이번에 알아보려는게 뭣이냐?!

해시값은 객체의 유니크한 값을 만들어줍니다.
그렇기 때문에 Hashable만 상속하고 있으면 Set 자료형에도 넣을 수 있고 Dictionary의 키값으로도 사용 가능합니다.
그런데 여기서 궁금증이 생겼습니다.

hash값으로 값 비교하는게 빠를까 Equatable로 값 비교하는게 빠를까?

바로 테스트를 해봅시다.

// Hashable
struct iPhone: Hashable {
    let name: String
    let storage: Int
}

// Equatable
struct iPhone: Equatable {
    let name: String
    let storage: Int
}

이렇게 기기명이랑 용량을 가진 iPhone이란 구조체를 각각 만들었습니다.
먼저 해시값이 잘 나오는지 확인하겠습니다.

let iPhone13_pro128 = iPhone(name: "13pro", storage: 128)
print(iPhone13_pro128.hashValue)	// -1087909095493923794

let iPhone13_pro128_2 = iPhone(name: "13pro", storage: 128)
print(iPhone13_pro128_2.hashValue)	// -1087909095493923794

let iPhone13_pro256 = iPhone(name: "13pro", storage: 256)
print(iPhone13_pro256.hashValue)	// -1747077728359295826

생각한대로 잘 나옵니다.
기기명과 용량이 같으면 동일한 해시값이 나왔고 용량만 다르더라도 다른 해시값이 나오는 걸 보실 수 있습니다.

자 그럼 Hashable이랑 Equatable 비교 성능 테스트를 해봅시다.
테스트 방법은 다음과 같습니다.

// 6종류의 아이폰 10만대 만들기
let iPhones = (0...99999).map { index -> iPhone in
    switch index % 5 {
    case 0:
        return iPhone(name: "11", storage: 64)
    case 1:
        return iPhone(name: "12mini", storage: 128)
    case 2:
        return iPhone(name: "12pro", storage: 256)
    case 3:
        return iPhone(name: "12pro", storage: 512)
    case 4:
        return iPhone(name: "13pro", storage: 128)
    default:
        return iPhone(name: "13pro", storage: 256)
    }

}

// 앞으로 찾을 아이폰
let iPhone13_pro128 = iPhone(name: "13pro", storage: 128)

// 비교 시간 체크
let start = CFAbsoluteTimeGetCurrent()
let iPhone13_pro128_arr = iPhones.filter { $0 == iPhone13_pro128 }
let diff = CFAbsoluteTimeGetCurrent() - start

print("Took \(diff) seconds")

총 3번씩 테스트했고 결과는 다음과 같습니다.

// Equatable
// 0.8124189376831055
// 0.7504860162734985
// 0.763375997543335

// Hashable
// 0.7399230003356934
// 0.7337720394134521
// 0.7278430461883545

미묘한 차이지만 Hashable 3연승!

유의미한 결과는 아니지만 그래도 Hashable이 더 빨랐습니다.
제가 생각하기에 원인은 Hashable에서 구조체 인스턴스를 생성할 때 같이 hash값도 만들기 때문에
미리 만들어 둔 hash값을 이용해서 비교하느라 더 빨랐던게 아닌가 생각됩니다.
(인스턴스 생성 시간까지 포함해서 퍼포먼스 비교해보면 더 느릴지도요...)

그래서 equal 체크를 할 때도 Hashable을 상속해서 해도 될듯합니다.
(Hashable 구현부를 보시면 Equatable을 상속하고 있어서 Equatable로 할 수 있는거 다 가능합니다.)

Equatable을 무조건 써야할 때라면 예제에서 '아이폰 기기명만 같아도 같은 기기로 취급한다' 라는 커스텀한 비교문을 만들고 싶을 때 사용하시면 될 듯 합니다.

솔직히 성능차이가 너무 없어서 그냥 취향에 따라하시면 됩니다.

좋은 웹페이지 즐겨찾기