|
昨日のカウンタ: 今日のカウンタ: |
SwiftとObjective-Cの速度比較をすると、Swiftの方が速かったり遅かったりします。どういう時にSwiftの方が速いのかがわかれば、速いコードを生成する方法もそこからわかると思って簡単な例から速度の比較をしています。 例えばこんな例。長さ1000000のInt型(Objective-CではNSInteger型)の配列を用意して簡単な計算結果を書き込んでいきます。
ObjC: - (void) clear:(NSInteger)val { for (int i = 0; i < 1000000; i ++) { array[i] = i & val; } } Swift: mutating func clear(val : Int) { for i in 0 ..< 1_000_000 { array[i] = i & val } }
arm64でビルドしてiPhone6で速度比較をしてみるとこんな感じみたいです。
2014-12-28 13:11:46.278 ASMTest[14858:3959193] swift: 0.00826001167297363 2014-12-28 13:11:46.296 ASMTest[14858:3959193] objc: 0.0162650346755981
順序を入れかえてもこんなもんの数値なので有意に速度が違うんでしょうかね。
コンパイル結果のアセンブリコードを眺めてみるとこんな感じみたいです。 先ずはObjective-Cの場合。
ObjC: LBB1_1: and x11, x8, x2 // x8がi, x2がval str x11, [x9, x8, lsl #3] // 配列arrayに計算結果を書込み (x9がarrayのアドレス) add x8, x8, #1 // i += 1 cmp x8, x10 // iと1000000の比較 b.ne LBB1_1
素直なコードです。(この箇所を特定するのはあんまり素直じゃないですが)
ではSwiftの方はどうかと言うと
Swift: LBB0_1: and x25, x24, x20 // x24がi、x20がval add x24, x24, #1 // i += 1 str x25, [x21, x22] // 配列arrayに計算結果を書き込み (x21がarray中身のアドレス) add x22, x22, #8 // array中身先頭からのオフセット cmp x24, x23 // iと1000000の比較 b.ne LBB0_1
という具合で変数iを格納するレジスタ(x24)と配列先頭からのオフセット用のレジスタ(x22)を分けているぐらいが、Objective-C側との違いぐらいなものです。 実際にはSwift側では、読みにくくなるので上のコードからは削っていますが、_swift_retainとか__swift_isUniquelyReferencedとかってのをループ内で呼び出したりしています。 どうしてそれでここまで速度に差が出るのやら、正直よくわかりませんでした。orz
という具合でしまりのない記事でした。でもSwiftってObjective-Cに比べて遅いと思われてるかも知れないけど、そんなことないんですよってことはわかると思います。(ぉぃ)
そんなこんなで私も書かせて頂きました「開発のプロが教える Swift標準ガイドブック」がクリスマスに発売となりました。 Objective-Cの経験のある方ならSwift書くときにどういう風に考えるかなー、どこでつまづくかなーって考えて、話し合って書いていきました。 Objective-CにはないGenericとかOptionalについても(私の執筆箇所じゃないですが)わかりやすく書けていると思います。 structやclassのつまづきやすいところもけっこうネチネチ調べて書いていますので、中級者以上の方も何かしら新しい発見があるのではないかと思います。 年末年始の休みのお供にぜひお買い求め下さい。
amazonのページはこちらです。