[Swift] 同じ値を毎回代入するのと同じ値じゃない時だけ代入するのってどっちが早いのか今更だけど検証した


モチベーション

varで宣言された値があるとします。

var foo = false

それを上書きするとします。

foo = true

ということを複数回繰り返すとします。


(0...10000).forEach { _ in
    foo = true
}

この時に毎回trueを代入しても、fooがfalseの時だけ代入しても結果fooはtrueになります。


(0...10000).forEach { _ in
    foo = true
}

(0...10000).forEach { _ in

    if foo { return }

    foo = true
}

// どっちにしろfooはtrueになる。

今更なんですが、パフォーマンス的にはどっちがいいのか気になったので検証してみました。
(もう誰か試してる気がするけど簡単にできそうだったので今のバージョンで改めてということでお許しください。。。)

仮説としては毎回代入する方がメモリをいじる分遅くなる気がします。

計測方法

こちらを参考にさせていただきました。

上記の方法で同じ繰り返しの処理の中に毎回値を代入するパターンと代入が必要な時だけ代入するパターンの2つを挟んでみて、最終的にかかった時間を計測します。

計測環境

  • Swift5.4
  • Xcode12.5

Playgroundで試しています。

パターン1: 毎回代入する場合

こちらを実行してみます。


var foo = false

let start = Date()

(0...100000).forEach { _ in
    foo = true
}

let elapsed = Date().timeIntervalSince(start)

print("result: " + elapsed.description)

結果は以下になりました。

"result: 1.4446409940719604\n"

1.5秒くらいですね。結構かかりました

パターン2: 代入する必要なければreturnする場合

こちらを実行してみます。


var foo = false

let start = Date()

(0...100000).forEach { _ in

    if foo { return }

    foo = true
}

let elapsed = Date().timeIntervalSince(start)

print("result: " + elapsed.description)

結果は以下になりました。

"result: 0.31178009510040283\n"

大体0.3秒です。パターン1と比べると結構差がつきました。

結論

重複した値を代入するより、重複のチェックをして重複しない時だけ代入した方が早そうです。

よくViewのUtilityメソッドでtranslatesAutoresizingMaskIntoConstraintsを毎回falseにするコードとか見かけるんですが、そういう時もtrueかどうかチェックして必要な時だけfalseを代入する方が早そうだよってコメントしてみようと思います。