都内で働くSEの技術的なひとりごと / Technical soliloquy of System Engineer working in Tokyo

都内でサラリーマンやってます。SQL Server を中心とした (2023年からは Azure も。) マイクロソフト系(たまに、OSS系などマイクロソフト以外の技術も...)の技術的なことについて書いています。日々の仕事の中で、気になったことを技術要素関係なく気まぐれに選んでいるので記事内容は開発言語、インフラ等ばらばらです。なお、当ブログで発信、発言は私個人のものであり、所属する組織、企業、団体等とは何のかかわりもございません。ブログの内容もきちんと検証して使用してください。英語の勉強のため、英語の

.NET アプリケーションの高速化について探し始めてみた - その5 - ( ConcurrentDictionary のパフォーマンス計測 )

 .NET アプリケーションの高速化について探し始めてみた - その4 - で取り上げた ConcurrentDictionary のパフォーマンスを計測してみたいと思います。検証しようかと思ったら、仮想環境を格納してある外付けハードディスクを忘れてしまいました...こんな時は、やっぱり Windows Azure です。下図通り、Visual Studio 2013 Preview が使用できるので、Azure 環境を使用して検証してみたいと思います。

f:id:koogucc11:20130908150315j:plain

 仮想マシンのサイズは『M』で、CPU:2コア、2.10GHz, メモリ:3.5G の環境を作成しました。コーヒーを飲みながら、検証ロジックを考えている間にプロビジョニングが終了しました。プロビジョニングが速いですね。

f:id:koogucc11:20130908192023j:plain

 Visual Studio 2013 Preview を今回はじめて使ったので、とりあえず画面ショット。

f:id:koogucc11:20130908184217p:plain

 検証に使用するソースコードは下記の通りです。同一の条件とするため、要素の追加は、instance[key] = value、 取得は、TryGetValue(key, out value) メソッドを使用しています。

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string args)
        {
            const int MAXITEMS = 100000;
            var accessIndex = new List<string>(MAXITEMS);
            var list = new List<KeyValuePair<string, object>>();
            for (int i = 0; i < MAXITEMS; i++)
            {
                list.Add(new KeyValuePair<string, object>(i.ToString(), i));
                accessIndex.Add(i.ToString());
            }
            var r = new Random(Environment.TickCount);
            var randomIndexesList = new List<string>(MAXITEMS);

            while (accessIndex.Count > 0)
            {
                int index = r.Next(accessIndex.Count);
                string value = accessIndex[index];
                accessIndex.RemoveAt(index);
                randomIndexesList.Add(value);
            }

            string randomIndexes = randomIndexesList.ToArray();

            //ConcurrentDictionaryへの要素追加に関する計測
            var lisw = Stopwatch.StartNew();
            var cdictionary = new ConcurrentDictionary<string, object>();
            for (int i = 0; i < MAXITEMS; i++)
            {
                cdictionary[i.ToString()] = i;
            }
            lisw.Stop();
            Console.WriteLine("ConcurrentDictionary(Add) - {0,10} ms", lisw.ElapsedMilliseconds);

            //Dictionaryへの要素追加に関する計測
            var ldsw = Stopwatch.StartNew();
            var dictionary = new Dictionary<string, object>();
            for (int i = 0; i < MAXITEMS; i++)
            {
                dictionary[i.ToString()] = i;
            }
            ldsw.Stop();
            Console.WriteLine("Dictionary(Add) - {0,10} ms", ldsw.ElapsedMilliseconds);

            //ConcurrentDictionaryへの要素取得に関する計測
            var igsw = Stopwatch.StartNew();
            for (int index = 0, indexMax = randomIndexes.Length; index < indexMax; index++)
            {
                string i = randomIndexes[index];
                object value;
                cdictionary.TryGetValue(i, out value);
            }
            igsw.Stop();
            Console.WriteLine("ConcurrentDictionary(TryGetValue) - {0,10} ms", igsw.ElapsedMilliseconds);

            //Dictionaryへの要素取得に関する計測
            var dgsw = Stopwatch.StartNew();
            for (int index = 0, indexMax = randomIndexes.Length; index < indexMax; index++)
            {
                string i = randomIndexes[index];
                object value;
                dictionary.TryGetValue(i, out value);
            }
            dgsw.Stop();
            Console.WriteLine("Dictionary(TryGetValue) - {0,10} ms", dgsw.ElapsedMilliseconds);
            Console.Read();
        }
    }
}

※結果は、下図の通りです。

要素 = 100,000の場合

f:id:koogucc11:20130908190840j:plain

要素 = 10,000の場合

f:id:koogucc11:20130908191239j:plain

要素 = 1,000の場合

f:id:koogucc11:20130908191355j:plain

要素 = 100の場合

f:id:koogucc11:20130908191503j:plain

 Dictionary のほうが若干高速(要素数が多い場合、追加に関しては ConcurrentDictionary  が高速)なようですが、スレッドセーフであること、AddOrUpdate, GetOrAdd などの便利メソッドの存在を考えると、ConcurrentDictionary を使用したいですね。.NETFramework 4.5 でも様々な機能追加がされていますね。全然ついて行けてないです.......