LoginSignup
8
7

More than 3 years have passed since last update.

C#高速/最適化メモ

Last updated at Posted at 2020-01-12

概要

色々な高速化などの噂について検証してみました
探せばいくらでもあるforとforeachの速度などは載せていません

なるべく二進数換算で小さい値に

2進数換算をした時に、1の数がなるべく少ない方が高速らしいという噂を聞いてやってみた

結果

+n 二進数換算 結果 +m%(+2基準)
+2 10 138459ms 0%
+127 1111111 148959ms +7%
+128 10000000 139022ms +0.4%

コード

sample.cs
var sw = new System.Diagnostics.Stopwatch();

            //-----------------
            // 計測開始
            sw.Start();

            // ★処理A
            for(int i = 0; i < 100000000; i++) {
                int num = 0;
                for(int j = 0; j < 1000; j++) {
                    num += 2;
                }
            }

            // 計測停止
            sw.Stop();

            // 結果表示
            Console.WriteLine("■処理Aにかかった時間");
            Console.WriteLine($" {sw.ElapsedMilliseconds}ミリ秒");

            sw.Reset();

            sw.Start();

            // ★処理B
            for (int i = 0; i < 100000000; i++) {
                int num = 0;
                for (int j = 0; j < 1000; j++) {
                    num += 127;
                }
            }

            // 計測停止
            sw.Stop();

            // 結果表示
            Console.WriteLine("■処理Bにかかった時間");
            Console.WriteLine($" {sw.ElapsedMilliseconds}ミリ秒");

            sw.Reset();

            sw.Start();

            // ★処理C
            for (int i = 0; i < 100000000; i++) {
                int num = 0;
                for (int j = 0; j < 1000; j++) {
                    num += 128;
                }
            }

            // 計測停止
            sw.Stop();

            // 結果表示
            Console.WriteLine("■処理Cにかかった時間");
            Console.WriteLine($" {sw.ElapsedMilliseconds}ミリ秒");

            System.Threading.Thread.Sleep(10000);
        }

補足

1000回の足し算を1億回やってこの程度(+7%)なのであまり気にしなくていいかもしれない
あと1000回の足し算を1000回程度ならPCの調子か、+128の方が遅いという結果になることも多少あったので、気休め程度に。

ビットシフトを使う

2の乗数で割り算をするとき、ビットシフトを使うと高速らしいという話を検証

結果

やり方 結果 +n%(/=基準)
/= 20798ms 0%
= num/2 20660ms -1%
num>>=1 4429ms -79%

コード

sample.cs
for(int i = 0; i < 10000000; i++) {
    int num = int.MaxValue;
    while(num > 2) {
        num /= 2; //この部分を変更
    }
}

補足

処理時間が5分の1……!
/=2とnum=num/2の差については誤差らしいというのを次項で説明

num/=2とnum=num/2

VisualStudioでは逆アセンブリという機能があり、それでデコンパイル状態のコード(アセンブリ言語?)を見ることができる
そこで見てみると、同じらしい

num /= 2;
mov         eax,dword ptr [ebp-44h]  
mov         ecx,2  
cdq  
idiv        eax,ecx  
mov         dword ptr [ebp-44h],eax  

num2 = num2 / 2;
mov         eax,dword ptr [ebp-48h]  
mov         ecx,2  
cdq  
idiv        eax,ecx  
mov         dword ptr [ebp-48h],eax 

全く同じ処理をしているので、全く同じ速度ということになるはずということで、誤差ということが判明

構造体とクラス

構造体の方が早いらしい。ただし一定以上のバイト数になるとクラスの方がいいらしい

結果

バイト数 構造体 クラス 処理時間(構造体を100%としたとき)
4 1731ms 5407ms 312%
16 1725ms 5916ms 342%
20 1808ms 6341ms 350%
32 1898ms 7399ms 390%
40 2076ms 7178ms 345%
44 9946ms 8416ms 85%
60 10366ms 8296ms 80%
64 8557ms 9155ms 107%
104 11142ms 10512ms 94%
128 8568ms 12236ms 143%

:thinking:

補足

構造体だと2の乗数で処理速度が上がるらしい
場合と数が大きいほどclassを使うメリットがあり、ぎりぎりまで高速化したい場合はstructか
ただ、さまざまなところで見た16bitが境目という話はなかったし、40~44の間で劇的に構造体が遅くなる理由は見当もつかないので、この話題について掘り下げるのは避けたいと思う

その他メモ

・stringは極力StringBuilderを使った方が早い
・ifとswitchはifの方が基本早い
・多分岐では上から順に出現頻度が多い条件を書くことで比較回数を減らすことができる

Unity編

・UnityのgameObject.tag=="hoge"より、gameObject.CompareTag("hoge")の方が早いらしい。gameObject.tagのアクセスが処理を食うとか
UI周りの最適化など
・Resourcesは出来る限り使わない
全般のパフォーマンス改善

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7