GGURUPiOS

[Swift] Dynamic Dispatch를 줄여 Class의 성능 향상시키기 본문

Swift/문법 파헤치기

[Swift] Dynamic Dispatch를 줄여 Class의 성능 향상시키기

꾸럽 2023. 10. 30. 21:34

안녕하세요.
이번에는 Class 성능을 향상 시키는 방법에 대해 알아보려고 합니다.
조금 오래되긴 했지만, 애플 스위프트 팀에서 올린 블로그 글 (현재는 운영을 안하는듯 하다. 마지막 글이 2016. 10. 12)을 참고하여 작성했습니다.

 

Increasing Performance by Reducing Dynamic Dispatch - Swift Blog

Get the latest news and helpful tips on the Swift programming language from the engineers who created it.

developer.apple.com


위 글에서는 Dynamic Dispatch를 줄여서, 성능을 향상시키는 방법에 대해 세가지 정도로 기술하고 있습니다.

Dynamic Dispatch? (동적 디스패치)

Swift 에서는 수퍼클래스에 선언된 메서드와 프로퍼티를 오버라이드 할 수 있다.
즉, 런타임에 어떤 메서드나 프로퍼티가 참조되는지 판단한 다음 간접 호출 또는 액세스를 수행해야 한다.
이러한 기술은 일정한 양의 런타임 오버헤드를 발생 시키는 대신, 언어 표현력? 을 향상시킨다고 한다.
(반대 개념은 Static Dispatch)

오버헤드? 어떤 프로세스, 동작 또는 작업을 수행하는 데 필요한 추가적인 비용, 시간, 또는 자원

성능적인 측면에서는 이러한 오버헤드가 바람직 하지 않은 경우가 많다.

이러한 동적 디스패치를 제거하여 성능을 개선하는 세가지 방법을 알아봅시다.


1. 오버라이드가 필요 없다면 final 키워드 사용하기

final 키워드는 override할 수 없음을 나타내는 키워드

final 키워드를 사용하면 컴파일러는 Dynamic Dispatch 를 제거할 수 있다.
즉 오버라이드를 하지 않기 때문에 간접호출 할 필요가 없음
Static Dispatch 로 처리되기 때문에 성능이 향상 됨.

class ParticleModel {
	final var point = ( x: 0.0, y: 0.0 )
	final var velocity = 100.0

	final func updatePoint(newPoint: (Double, Double), newVelocity: Double) {
		point = newPoint
		velocity = newVelocity
	}

	func update(newP: (Double, Double), newV: Double) {
		updatePoint(newP, newVelocity: newV)
	}
}

// 위와 같이 프로퍼티나 함수에 final 키워드를 붙여도 되지만
// 아래처럼 class 자체에 final 키워드를 붙이는 경우가 더 많은것 같다.

final class ParticleModel {
	var point = ( x: 0.0, y: 0.0 )
	var velocity = 100.0
	// ...
}



2. private 키워드를 적용해서 한 파일에서 참조된 선언에 대해 final 추론하기

private 키워드를 사용하면 구현범위 내에서만으로 제한됨. (현재 파일로 범위가 제한된다, 옛날 문서라 이렇게 쓰여있는듯 -> fileprivate)
여튼, 이렇게 하면 컴파일러가 잠재적으로 오버라이딩 할 수 있는 모든 선언을 찾을 수 있음 (오버라이딩 여부를 추론 가능)
이런식으로 간접 호출을 제거할 수 있다.


3. Whole Module Optimization(전체 모듈 최적화?)를 사용하여 final 추론하기

 

내부 접근제어자 선언 시(기본값과 같음 internal)은 모듈 내에서만 볼 수 있음.
Swift는 일반적으로 모듈을 구성하는 파일을 개별적으로 컴파일하기 때문에, 컴파일러는 내부 선언의 오버라이딩 여부를 알 수 없음
Whole Module Optimization을 활성화 하면 모든 모듈이 동시에 컴파일 됨.
동시에 컴파일 되기 때문에, 오버라이딩 여부를 알 수 있고 final을 자동으로 선언해 준다.

현재는 자동으로 켜져있다고 함.

그러나 open, public 등(상위레벨)의 키워드는 외부 모듈에서도 접근이 가능 -> Dynamic Dispatch 로작동


그 외 클래스 성능을 증가시키는 방법

레퍼런스 카운팅 최소화, 순환참조 피하기
lazy 키워드 사용 -> 필요한 경우에만 초기화 
@inlinable 키워드 사용 -> 호출하는것이 아니라, 구현부를 복사해 가져오기 때문에 오버헤드 줄어듬

등등이 있다.