Swift の Array / Dictionary は最適化なしでは遅い (Xcode 6.1 / iOS 8.1 更新)

Swift の Array/Dictionary は最適化なしでコンパイルした場合, 実行速度が遅くなります. NSMutableArray/NSMutableDictionary と比べてもかなり遅い結果となります.

テストコード

この問題をテストするために単純なサンプルコードを作成しました. NSMutableArray と Swift の Array にそれぞれ 1,000,000 個の要素を追加するコードと, NSMutableDictionary と Swift の Dictionary に 100,000 個の要素を追加するコードです.

OS X の Swift は現時点で Beta とされているため, iOS アプリケーションとして作成しました. 利用したコードは GitHub で公開しています.

コンパイルと実行

Xcode でプロジェクトファイルを開き, コンパイルし実行します. アプリ内の Run Benchmark をタップするとテストを実行し, UIAlertView で結果を表示します.

Swift のコンパイラには Xcode 6.0.1 (6A317) の時点で, -Onone (最適化なし), -O (最適化あり), -Ounchecked (最適化あり, 実行時の様々なチェックを行わない) があります. これらの3種類の最適化オプションを切り替えてパフォーマンスを測定します.

-Ofast は Xcode 6 Beta 5 から -Ounchecked に変更されました.

テスト結果

テスト結果は以下のようになりました. 共通の環境は次の通りです: OS X Yosemite (14A329f) / Xcode 6.0.1 (6A317)

iPhone 5s Simulator / iOS 8 (12A365)

Comparison of Swift's Array/Dictionary and NSMutableArray/NSMutableDictionary (iPhone 5s Simulator)

Onone

 
NSMutableArray:      0.32 [sec]
Swift Array:         7.02 [sec]
NSMutableDictionary: 0.08 [sec]
Swift Dictionary:    2.04 [sec]

O

 
NSMutableArray:      0.11 [sec]
Swift Array:         0.06 [sec]
NSMutableDictionary: 0.05 [sec]
Swift Dictionary:    0.02 [sec]

Ounchecked

 
NSMutableArray:      0.11 [sec]
Swift Array:         0.10 [sec]
NSMutableDictionary: 0.05 [sec]
Swift Dictionary:    0.02 [sec]

iPhone 5s / iOS 8 (12A365)

Comparison of Swift's Array/Dictionary and NSMutableArray/NSMutableDictionary (iPhone 5s)

Onone

 
NSMutableArray:      0.80 [sec]
Swift Array:        29.15 [sec]
NSMutableDictionary: 0.19 [sec]
Swift Dictionary:    8.27 [sec]

O

 
NSMutableArray:      0.14 [sec]
Swift Array:         0.28 [sec]
NSMutableDictionary: 0.09 [sec]
Swift Dictionary:    0.10 [sec]

Ounchecked

 
NSMutableArray:      0.14 [sec]
Swift Array:         0.51 [sec]
NSMutableDictionary: 0.10 [sec]
Swift Dictionary:    0.10 [sec]

Simulator (x64) と iPhone 5s (arm64) で少し傾向が異なります.

どちらにも共通して言えることは, 最適化なしの場合, Swift の Array と Dictionary は圧倒的に遅く NSMutableArray と NSMutableDictionary に比べて数十倍の時間がかかっています.

最適化を行った場合はアーキテクチャにより傾向が異なり, Intel アーキテクチャの場合は Swift の Array と Dictionary の方が高速に実行でき, NSMutableArray と NSMutableDictionary に比べて約半分の時間で実行できるようになります. しかし, ARM アーキテクチャの場合は Swift の Array と Dictionary の方が遅く NSMutableArray と NSMutableDictionary に比べて約1〜2倍の時間がかかってしまいます.

まとめ

Swift の Array と Dictionary は最適化無しで実行すると非常に遅くなります. しかし, 最適化を行うと Intel アーキテクチャでは NSMutableArray や NSMutableDictionary 約半分の時間で, ARM アーキテクチャでは数倍の時間で実行できるようになります.

実際にアプリケーションを開発する場合, デバッグビルドは最適化なしで行うことが多いですが, Swift でこれを行うと予想以上にパフォーマンスが低下する可能性があります. コンパイル時間は長くなりますが, リリースするものと近いパフォーマンスで実行したい場合は, デバッグビルドでも最適化を行うほうが良さそうです.

今後のアップデートで改善されていくとは思いますが, Apple には Swift の最適化なしでの実行速度の改善と ARM アーキテクチャでの最適化の改善を望みたいところです.

追記: Xcode 6.1 / iOS 8.1 でのテスト結果

Xcode 6.1 と iOS 8.1 が正式リリースとなったため, 改めて iPhone 5s 実機と iPhone 5s Simulator でテストを行いました. 共通の環境は次の通りです: OS X Yosemite (14A388a) / Xcode 6.1 (6A1052d) / iOS 8.1 (12B411)

iPhone 5s Simulator / iOS 8.1 (12B411)

Comparison of Swift's Array/Dictionary and NSMutableArray/NSMutableDictionary (iPhone 5s Simulator / iOS 8.1)

Onone

 
NSMutableArray:      0.34  [sec]
Swift Array:         6.61  [sec]
NSMutableDictionary: 0.073 [sec]
Swift Dictionary:    2.58  [sec]

O

 
NSMutableArray:      0.12  [sec]
Swift Array:         0.014 [sec]
NSMutableDictionary: 0.048 [sec]
Swift Dictionary:    0.036 [sec]

Ounchecked

 
NSMutableArray:      0.12 [sec]
Swift Array:         0.014 [sec]
NSMutableDictionary: 0.047 [sec]
Swift Dictionary:    0.033 [sec]

iPhone 5s / iOS 8.1 (12B411)

Comparison of Swift's Array/Dictionary and NSMutableArray/NSMutableDictionary (iPhone 5s / iOS 8.1)

Onone

 
NSMutableArray:      0.88 [sec]
Swift Array:        27.9  [sec]
NSMutableDictionary: 0.21 [sec]
Swift Dictionary:   10.9  [sec]

O

 
NSMutableArray:      0.14  [sec]
Swift Array:         0.029 [sec]
NSMutableDictionary: 0.085 [sec]
Swift Dictionary:    0.16  [sec]

Ounchecked

 
NSMutableArray:      0.14  [sec]
Swift Array:         0.031 [sec]
NSMutableDictionary: 0.088 [sec]
Swift Dictionary:    0.15  [sec]

追記: Xcode 6.1 / iOS 8.1 まとめ

Xcode 6.1 と iOS 8.1 では Swift の Array が大きく高速化していることがわかります. 最適化ありの場合 Intel アーキテクチャ, ARM アーキテクチャともに, NSMutableArray よりも数倍〜10倍程度高速になっています.

一方で Swift の Dictionary の速度にはあまり改善が見られないようです. 今後のアップデートでの改善に期待です.