ラベル 速度比較 の投稿を表示しています。 すべての投稿を表示
ラベル 速度比較 の投稿を表示しています。 すべての投稿を表示

2017年11月21日火曜日

文字列比較の速度を比べてみる


検証内容

文字列の一致についてどれが一番早いかを比較。
調査する種類は、以下の3つとする


  • String.CompareTo
  • ==演算子
  • String.Compare




検証コード

static void StringCompare()
{
    var count = 100000;
    var ret = false;
    var inputStr1 = "aBcDeFgHiJkLmNoPqRsTuVwXyZ0123456789";
    var inputStr2 = "abCdEfGhIjKlMnOpQrStUvWxYz0123456789";
    Console.WriteLine("---------------------------------");
    Console.WriteLine($"ループ回数:{count:d}");

    //-----------------------------------------------------------------
    var time = Stopwatch.StartNew();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr1.ToLower().CompareTo(inputStr2.ToLower()) ==0;
    }
    time.Stop();
    Console.WriteLine($"CompareTo : {time.ElapsedMilliseconds}ms");

    //-----------------------------------------------------------------
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = (inputStr1.ToLower() == inputStr2.ToLower());
    }
    time.Stop();
    Console.WriteLine($"== : {time.ElapsedMilliseconds}ms");

    //-----------------------------------------------------------------
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = String.Compare(inputStr1 ,inputStr2,true) == 0;
    }
    time.Stop();
    Console.WriteLine($"String.Compare : {time.ElapsedMilliseconds}ms");
}

結果

---------------------------------
ループ回数:100000
CompareTo : 108ms
== : 74ms
String.Compare : 104ms
---------------------------------
ループ回数:100000
CompareTo : 112ms
== : 61ms
String.Compare : 79ms
---------------------------------
ループ回数:100000
CompareTo : 88ms
== : 47ms
String.Compare : 77ms
---------------------------------
ループ回数:100000
CompareTo : 105ms
== : 61ms
String.Compare : 81ms
---------------------------------
ループ回数:100000
CompareTo : 103ms
== : 45ms
String.Compare : 99ms

結論

==演算子が速い!!
でも、10万回も回しての数十msなら、どちらでもよいかも。
っていうか、こちらについても相当シビアな環境じゃなきゃ影響なし。

2017年11月20日月曜日

C#で文字が含まれるかどうかの判定速度を比較してみた


検証内容

文字列の中から、1文字(char)が含まれるかどうかを調べる。
調査する種類は、以下の4つ


  • Contains("文字列")
  • Contains('文字')
  • IndexOf("文字列")
  • IndexOf('文字')


検証コード


static void TestContains()
{
    var count = 100000;
    var ret = false;
    var inputStr = "abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefg";
    Console.WriteLine("---------------------------------");
    Console.WriteLine($"ループ回数:{count:d}");
    var time = Stopwatch.StartNew();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr.Contains("g");
    }
    time.Stop();
    Console.WriteLine($"Contains(\"g\") : {time.ElapsedMilliseconds}ms");
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr.Contains('g');
    }
    time.Stop();
    Console.WriteLine($"Contains('g') : {time.ElapsedMilliseconds}ms");
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr.IndexOf("g") > 0;
    }
    time.Stop();
    Console.WriteLine($"IndexOf(\"g\") : {time.ElapsedMilliseconds}ms");
    time.Restart();
    for (var i = 0; i < count; i++)
    {
        ret = inputStr.IndexOf('g') > 0;
    }
    time.Stop();
    Console.WriteLine($"IndexOf('g') : {time.ElapsedMilliseconds}ms");
}

結果

ループ回数:100000
Contains("g") : 39ms
Contains('g') : 113ms
IndexOf("g") : 432ms
IndexOf('g') : 8ms
---------------------------------
ループ回数:100000
Contains("g") : 29ms
Contains('g') : 115ms
IndexOf("g") : 417ms
IndexOf('g') : 7ms
---------------------------------
ループ回数:100000
Contains("g") : 30ms
Contains('g') : 115ms
IndexOf("g") : 300ms
IndexOf('g') : 5ms
---------------------------------
ループ回数:100000
Contains("g") : 27ms
Contains('g') : 80ms
IndexOf("g") : 287ms
IndexOf('g') : 4ms
---------------------------------
ループ回数:100000
Contains("g") : 23ms
Contains('g') : 74ms
IndexOf("g") : 335ms
IndexOf('g') : 6ms

結論

1文字の検索なら、IndexOfが速い!!
でも、10万回も回しての数百msなら、どちらでもよいかも。
っていうか、Contains("文字列")でもそこそこ速いから、相当シビアな環境じゃなきゃ影響なし。

2017年11月19日日曜日

C#でStringBuilderと+= 演算子の速度比較をしてみた


概要

StringBuilderと+= 演算子の速度差が気になったので、実験してみました。
方法としては、以下のテストコードを5回繰り返し、結果を確認しています。

テストコード

static void TestAppendText()
{
    var count = 100000;
    Console.WriteLine("---------------------------------");
    Console.WriteLine($"ループ回数:{count:d}");
    var time = Stopwatch.StartNew();
    var message = string.Empty;
    var append = @"append";
    for (var i = 0; i < count; i++)
    {
        message += append;
    }
    time.Stop();
    Console.WriteLine($"String += : {time.ElapsedMilliseconds}ms");
    time.Restart();
    var builderMessage = new StringBuilder();
    for (int i = 0; i < count; i++)
    {
        builderMessage.Append(append);
    }
    time.Stop();
    Console.WriteLine($"StringBuilder: {time.ElapsedMilliseconds}ms");
}

結果

---------------------------------
ループ回数:100000
String += : 23382ms
StringBuilder: 1ms
---------------------------------
ループ回数:100000
String += : 22175ms
StringBuilder: 1ms
---------------------------------
ループ回数:100000
String += : 23060ms
StringBuilder: 1ms
---------------------------------
ループ回数:100000
String += : 23978ms
StringBuilder: 1ms
---------------------------------
ループ回数:100000
String += : 22435ms
StringBuilder: 2ms

結論

明らかに、StringBuilderを使用したほうが早いという結果になりました。
やっぱり、StringBuilderのほうが早くていいよね。+=はだめだね。っていう結論にしてもいいのですが、
試しにループ回数を100回にした場合には、以下の結果になっています。

---------------------------------
ループ回数:100
String += : 0ms
StringBuilder: 0ms

ms単位での差が分かりません。
なので100回程度の文字列の連結であれば、どちらも気にならないと思います。
そもそも、文字列を10万回も結合しなければいけないコードを書く人が悪いと思います。

結論としては、StringBuilderをお勧めはするけど、強要はしないって感じでしょうかねぇ。

2017年11月8日水曜日

C#でDecimalの演算速度が遅いので速度比較


C#でDecimalの演算速度が遅い気がしたので、計測してみた。
比較対象は、天下の浮動小数点のDouble。


計測の際に使用したプログラム

private void Test()
{
    DecimalDivide();
    DoubleDivide();
}
private void DecimalDivide()
{
    var stopwatch = new System.Diagnostics.Stopwatch();
    stopwatch.Start();
    Decimal val = 10000;
    Decimal calc= 2m;
    for( Int32 i = 0; i < 10000; i++ )
    {
        val = val / calc;
    }
    stopwatch.Stop();
    Debug.WriteLine( stopwatch.ElapsedTicks );
}
private void DoubleDivide()
{
    var stopwatch = new System.Diagnostics.Stopwatch();
    stopwatch.Start();
    Double val = 10000;
    Double calc = 2.0;
    for( Int32 i = 0; i < 10000; i++ )
    {
        val = val / calc;
    }
    stopwatch.Stop();
    Debug.WriteLine( stopwatch.ElapsedTicks );
}

測定結果

速度差にして約5倍。計算が多くなってくると、ちょっと気になる差かも。。。
まぁ、基本的に、使用する型は、必要十分な型にすべきということですね。

Decimal:1309tick(1.3ms)
Double:224tick(0.24ms)

2016年9月2日金曜日

C#でParallelクラスを使って並列処理を高速化を速度計測

Parallelクラスを使って並列処理を高速化してみました。

環境としては、SurfacePro4でCPUは、i5です。
テストコードは、次の汚れきった目も当てられないコードになっています。

試したのは、foreach文、for文、Parallel.ForEach,Parallel.For(スレッド数は、デフォルト、8,4,2)の10種類です。

結果としては、予想通り、コア数と同程度が良いみたいですね。
ちなみに、スレッド数指定しない場合には、いくつで動くのか、わかる人いたら教えてください。
お願いします。

コード

/// <summary>
/// テスト実施
/// </summary>
/// <remarks>
/// 同じこといっぱい書きたくなかったのと、
/// クラス用意するのがいやだったのと、
/// 関数化するのが面倒だったので、
/// 汚コードです。
/// </remarks>
/// <param name="args"></param>
static void Main(string[] args)
{
    var count = 1000;
    var target = Enumerable.Range(0, count).ToList();
    var sw = new Stopwatch();
    var results = new List<String>();
    var stringWidth = 40;
    var option = new ParallelOptions();
    // 結果保持のためのAction
    var ResultAdd = new Action<String, TimeSpan>((msg, ellapsed) =>
        {
            results.Add(
                    String.Format(
                    msg, sw.Elapsed).PadLeft(stringWidth));
        });
    // 匿名配列で表示メッセージと実行処理を登録
    var testMethod = new[]
        {
            // foreachで回す
            new {
                Msg ="foreach:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    foreach (var i in list)
                    {
                        Console.WriteLine(WeightMethod(i));
                    }
                })
            },
            // forで回す
            new {
                Msg ="for:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    for (Int32 i = 0; i < count; i++)
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    }
                })
            },
            // Parallel.ForEachで回す(オプション指定なし)
            new {
                Msg ="Parallel.ForEach:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    Parallel.ForEach(list, (i) =>
                    {
                        Console.WriteLine(WeightMethod(i));
                    });
                })
            },
            // Parallel.Forで回す(オプション指定なし)
            new {
                Msg ="Parallel.For:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    Parallel.For(0, count, (i) =>
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    });
                })
            },
            // Parallel.ForEachで回す(オプション指定:8)
            new {
                Msg ="Parallel.ForEach8:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 8;
                    Parallel.ForEach( list, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(i));
                    });
                })
            },
            // Parallel.Forで回す(オプション指定なし:8)
            new {
                Msg ="Parallel.For8:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 8;
                    Parallel.For( 0, count, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    });
                })
            },
            // Parallel.ForEachで回す(オプション指定:4)
            new {
                Msg ="Parallel.ForEach4:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 4;
                    Parallel.ForEach( list, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(i));
                    });
                })
            },
            // Parallel.Forで回す(オプション指定なし:4)
            new {
                Msg ="Parallel.For4:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 4;
                    Parallel.For( 0, count, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    });
                })
            },
            // Parallel.ForEachで回す(オプション指定:2)
            new {
                Msg ="Parallel.ForEach2:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 2;
                    Parallel.ForEach( list, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(i));
                    });
                })
            },
            // Parallel.Forで回す(オプション指定なし:2)
            new {
                Msg ="Parallel.For2:{0}",
                Method =new Action<List<Int32>>((list)=>
                {
                    option.MaxDegreeOfParallelism = 2;
                    Parallel.For( 0, count, option, (i) =>
                    {
                        Console.WriteLine(WeightMethod(list[i]));
                    });
                })
            },
        };
    for (var id = 0; id < testMethod.Length; id++)
    {
        sw.Reset();
        sw.Start();
        // 実行
        testMethod[id].Method(target);
        sw.Stop();
        // 結果書き込み
        ResultAdd(testMethod[id].Msg, sw.Elapsed);
    }
    foreach (var result in results)
    {
        Console.WriteLine(result);
    }
}
/// <summary>
/// 重たい処理もどき
/// </summary>
/// <remarks>
/// なんでもよい。
/// </remarks>
/// <param name="count"></param>
/// <returns></returns>
static UInt64 WeightMethod(Int32 count)
{
    var ret = 0UL;
    var max = 10000000 - count;
    for (var i = 0U; i < max; i++)
    {
        ret += i;
        ret -= i;
    }
    return ret;
}


結果
 

                foreach:00:00:36.3392310
                    for:00:00:36.3863514
       Parallel.ForEach:00:00:17.7727370
           Parallel.For:00:00:17.3482534
      Parallel.ForEach8:00:00:17.5221452
          Parallel.For8:00:00:18.8532388
      Parallel.ForEach4:00:00:16.3212531
          Parallel.For4:00:00:16.3745319
      Parallel.ForEach2:00:00:20.8530706
          Parallel.For2:00:00:20.0480644