Swiftでnilか否かで処理を分岐するときのOptional Bindingとnil比較の速度を検証してみた

Twitterで

というつぶやきを拝見しました。Optionalに値が入っている場合の分岐の速度ということですね。もう少し詳細に調べてみました。

以下のコードを実機iPhoneで動かしてみます。

debug設定、つまり-OnoneでコンパイルしてrunSpeedTestsを実行すると

Execution time - Optional Binding: 0.802894949913025
Execution time - eq not nil: 8.99928903579712
Execution time - switch: 0.802114963531494

このような結果になりました。nilとの比較ではOptional Bindingよりも10倍以上の時間がかかっています。Swiftは!=は内部でswitchで検査しているようです。しかしswitchは最も速いです(何度実行してもほぼ最速)。となると!=メソッドの呼び出しに時間がかかっているのでしょうか。

さて次にrelease設定、つまり-Oでコンパイルして実行してみましょう。結果は…

Execution time - Optional Binding: 0.0
Execution time - eq not nil: 0.0
Execution time - switch: 0.0

何も処理が書かれていないので最適化されて実行されていないようです。ですので簡単な処理を足してみます。また、速度の違いがわかりやすいように実行回数も増やしてみます。

これを実行すると

Execution time - Optional Binding: 2.11918199062347
Execution time - eq not nil: 2.10913693904877
Execution time - switch: 2.10952198505402

のようになりました。驚くことに!= nilがOptional Bindingより速くなっています。複数回実行しても!=の方が高速なようです。!=メソッドはインライン化されているので最適化で高速化されているようです。(ちなみに!=とswitchは!=が速い時もあればswitchが速い時もあり、インライン化されて同等の処理のようです。)

ということで、Optional Bindingでnilを検査するより!= nilを使った方が分かりやすさでも速度の面でも良さそうだという結論に至りました。