石野光仁 Blog

開発、C#、ASP.NET、アイライトの活動について、いろいろ

AILight Banner
AILight Blog

プロフィール

石野光仁 Blog

目次

Blog 利用状況

記事分類

過去の記事

タグ

dynamic型を利用した時のパフォーマンス調査

今年は、Advent Calender に初参加してみました。
この記事は、C#側なのですが、ASP.NETにも参加しており、同じ日を設定してしまいました・・・

本人的には、同じ日なら忘れることがないから完璧!! って思っていたのですが、
記事を2本書く大変さを忘れていました(笑)

さてと、愚痴はこれぐらいにしておいて、、、早速記事を紹介したいと思います。


今回は、dynamicを使用した時のパフォーマンスを調べてみました。
テストの方法として、、リフレクション、キャスト、ダイナミックそれぞれを利用した時の実行時間をみてみたいと思います。
サンプルはシンプルに作成し、それぞれobject型で受け取り、引数に1時間足してみるというサンプルです。
実行環境は、Windows 8、Visual Studio 2012 Releaseビルド、Visual Studio上からの実行です。
対象のフレームワーク、.NET Framework 4.5、コンソールアプリです。

呼び出しは、1回と、1千万回 それぞれの呼び出し結果について比較してみました。

サンプルプログラム
using System;
using System.Diagnostics;

namespace ConsoleApplicationForDynamicTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var stopWatch = new Stopwatch();
            var datetime = DateTime.Now;

            for (var loopIndex = 1; loopIndex <= 2; loopIndex += 1)
            {
                Console.WriteLine("テスト:" + loopIndex.ToString());
                for (var loopCount = 1; loopCount <= 10000000; loopCount += (10000000 - 1))
                {
                    Console.WriteLine(" LoopCount:" + loopCount.ToString());
                    stopWatch.Reset();
                    stopWatch.Start();
                    for (int index = 0; index < loopCount; index++)
                        RefrectionTestMethod(datetime);
                    stopWatch.Stop();
                    Console.WriteLine("MethodInfo:".PadLeft(13) + stopWatch.Elapsed.ToString());

                    stopWatch.Reset();
                    stopWatch.Start();
                    for (int index = 0; index < loopCount; index++)
                        CastTestMethod(datetime);
                    stopWatch.Stop();
                    Console.WriteLine("Cast:".PadLeft(13) + stopWatch.Elapsed.ToString());

                    stopWatch.Reset();
                    stopWatch.Start();
                    for (int index = 0; index < loopCount; index++)
                        DynamicTestMethod(datetime);
                    stopWatch.Stop();
                    Console.WriteLine("Dynamic:".PadLeft(13) + stopWatch.Elapsed.ToString());
                }
            }
            Console.ReadKey();
        }

        public static void RefrectionTestMethod(object target)
        {
            var methodInfo = typeof(DateTime).GetMethod("AddHours");
            target = methodInfo.Invoke(target, new object[] { 1 });
        }

        public static void CastTestMethod(object target)
        {
            if (target is DateTime)
            {
                var localTarget = (DateTime)target;
                target = localTarget.AddHours(1);
            }
        }

        public static void DynamicTestMethod(object target)
        {
            dynamic localTarget = target;
            localTarget = localTarget.AddHours(1);
        }
    }
}

実行結果
 

ちょっと予測した結果と違っていて非常に面白いですね。
テスト1回目は、関数を呼び出すときのオーバーヘッドが非常にかかっています。
Dynamicを使われているところを呼び出すと、信じられないほどのオーバーヘッドがかかっていることがわかるかと思います。
しかし、1千万回呼び出したときには、MethodInfoよりよいパフォーマンスをだしていることが分かります。

テスト2回目は、関数呼び出しのオーバーヘッドがほとんどなくなった状態だと思われます。
ループカウントが、1回の場合、MethodInfoがとても遅く見えます。

今回のテストでは、Dynamicのパフォーマンスが非常良いことが分かります。
1回目の呼び出しが遅いのだけはちょっとだけ注意が必要ですね。
パフォーマンスの呼び出し確認を1回だけで行った場合、恐ろしく遅い関数に見えてしまって、間違ったチューニングを行ってしまう可能性があります。

ということで、適材適所で使うかと思いますが、Dynamicは必要十分のパフォーマンスが出ていますので、使って問題ないと思います。
と自分に言い聞かせました(笑)

以上が、C# Advent Calender 2012 参加記事でした。
http://atnd.org/events/33905


 

投稿日時 : 2012年12月23日 14:45


コメントを追加

タイトル
名前
URL
コメント