Open棟梁Project - マイクロソフト系技術情報 Wiki
こちらでは、メモリに保持可能なデータ量の場合の設計ディシジョンについて説明します。
この場合、メモリの大量消費による同時実行性の低下やCPU時間が問題となります。
メモリ上のデータへのアクセス時間を1億回実行して測定してみました。
100000000回 Only for :ExT:277[msec], CT:281[msec], KT:0[msec], UT:281[msec] → forループのオーバーヘッド if :ExT:291[msec], CT:281[msec], KT:0[msec], UT:281[msec] → ifステートメント intRef :ExT:217[msec], CT:218[msec], KT:0[msec], UT:218[msec] → int変数の参照+代入 strRef :ExT:216[msec], CT:218[msec], KT:0[msec], UT:218[msec] → string変数の参照+代入 crRef :ExT:281[msec], CT:281[msec], KT:0[msec], UT:281[msec] → オブジェクト・メンバ変数の参照+代入 arryRef :ExT:234[msec], CT:234[msec], KT:0[msec], UT:234[msec] → 配列の参照+代入 arryRef4 :ExT:715[msec], CT:718[msec], KT:0[msec], UT:718[msec] → 4次元配列の参照+代入 lstRef :ExT:498[msec], CT:499[msec], KT:0[msec], UT:499[msec] → リストの参照+代入 lstRef4 :ExT:1570[msec], CT:1560[msec], KT:0[msec], UT:1560[msec] → 4階層リストの参照+代入 dicRef :ExT:2996[msec], CT:3011[msec], KT:0[msec], UT:3011[msec] → Dictionaryの参照+代入 dicRef4 :ExT:11695[msec], CT:11684[msec], KT:0[msec], UT:11684[msec] → 4階層Dictionaryの参照+代入
class Program { static void Main(string[] args) { int i = 0; const int num = 100000000; Console.WriteLine(num.ToString() + "回"); PerformanceRecorder pr = new PerformanceRecorder(); //-------------------------------------------------- // ウォームアップ //-------------------------------------------------- for (i = 0; i < num; i++) { } for (i = 0; i < num; i++) { } //-------------------------------------------------- // Only for //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { } Console.WriteLine("Only for:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // ifステートメント //-------------------------------------------------- bool bln = true; //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { if (bln) { } } Console.WriteLine("if:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // intの参照と代入 //-------------------------------------------------- int intVal = 0; int intRef = 100; //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { intVal = intRef; } Console.WriteLine("intRef:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // stringの参照と代入 //-------------------------------------------------- string strVal = ""; string strRef = "aaa"; //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = strRef; } Console.WriteLine("strRef:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // クラスメンバの参照と代入 //-------------------------------------------------- ClassRecord crRef = new ClassRecord(); //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = crRef.G; } Console.WriteLine("crRef:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // 配列添字での参照と代入 //-------------------------------------------------- string[] arryRef = new string[] { strRef, strRef, strRef, strRef, strRef, strRef, strRef }; //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = arryRef[6]; } Console.WriteLine("arryRef:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // 4次元配列添字での参照と代入 //-------------------------------------------------- string[, , ,] arryRef4 = new string[1, 1, 1, 1] { { { {""} } } }; //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = arryRef4[0, 0, 0, 0]; } Console.WriteLine("arryRef4:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // Generic List 添字での参照と代入 //-------------------------------------------------- List<string> lstRef = new List<string>(); lstRef.Add(strRef); lstRef.Add(strRef); lstRef.Add(strRef); lstRef.Add(strRef); lstRef.Add(strRef); lstRef.Add(strRef); lstRef.Add(strRef); //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = lstRef[6]; } Console.WriteLine("lstRef:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // 4階層Generic List 添字での参照と代入 //-------------------------------------------------- List<List<string>> lstRef2 = new List<List<string>>(); List<List<List<string>>> lstRef3 = new List<List<List<string>>>(); List<List<List<List<string>>>> lstRef4 = new List<List<List<List<string>>>>(); lstRef.Add(strRef); lstRef2.Add(lstRef); lstRef3.Add(lstRef2); lstRef4.Add(lstRef3); //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = lstRef4[0][0][0][0]; } Console.WriteLine("lstRef4:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // Generic Dictionary 添字での参照と代入 //-------------------------------------------------- Dictionary<string, string> dicRef = new Dictionary<string, string>(); dicRef["A"] = strRef; dicRef["B"] = strRef; dicRef["C"] = strRef; dicRef["D"] = strRef; dicRef["E"] = strRef; dicRef["F"] = strRef; dicRef["G"] = strRef; //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = dicRef["G"]; } Console.WriteLine("dicRef:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // 4階層Generic Dictionary 添字での参照と代入 //-------------------------------------------------- Dictionary<string, Dictionary<string, string>> dicRef2 = new Dictionary<string, Dictionary<string, string>>(); Dictionary<string, Dictionary<string, Dictionary<string, string>>> dicRef3 = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>(); Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>> dicRef4 = new Dictionary<string, Dictionary<string, Dictionary<string, Dictionary<string, string>>>>(); dicRef["G"] = strRef; dicRef2["G"] = dicRef; dicRef3["G"] = dicRef2; dicRef4["G"] = dicRef3; //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = dicRef4["G"]["G"]["G"]["G"]; } Console.WriteLine("dicRef4:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // 4階層Generic Dictionary 添字での参照と代入(With句的対策) //-------------------------------------------------- pr.StartsPerformanceRecord(); dicRef = dicRef4["G"]["G"]["G"]; for (i = 0; i < num; i++) { strVal = dicRef["G"]; } Console.WriteLine("dicRef4性能対策実施版:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // 4階層Generic Dictionary もしハッシュ・キーがintだったら //-------------------------------------------------- Dictionary<int, string> dicRefInt = new Dictionary<int, string>(); dicRefInt[0] = strRef; dicRefInt[1] = strRef; dicRefInt[2] = strRef; dicRefInt[3] = strRef; dicRefInt[4] = strRef; dicRefInt[5] = strRef; dicRefInt[6] = strRef; //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = dicRefInt[6]; } Console.WriteLine("dicRefハッシュ・キーがint:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- //-------------------------------------------------- // Generic Dictionary 添字での参照と代入(大量データ) //-------------------------------------------------- Dictionary<string, string> dicRefBigdata = new Dictionary<string, string>(); int j = 0; for(j = 0; j< 1000000; j++) { dicRefBigdata[j.ToString()] = strRef; } //-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = dicRefBigdata["999999"]; } Console.WriteLine("dicRefBigdata:" + pr.EndsPerformanceRecord()); //-------------------------------------------------- Console.ReadKey(); } }
メモリ上のアクセス時間は、配列や、Genericの4階層を使用し始めると
(余談:ifのオーバーヘッドはあまり無いようです。)
従って、データ保持は、
を使用することになると思います。
ということだと思います。
階層が増える場合、チューニング手段としてよくやる
VBのWithステートメントを使用する要領で、辿るポインタ数を減らします。
//-------------------------------------------------- pr.StartsPerformanceRecord(); for (i = 0; i < num; i++) { strVal = dicRef4["G"]["G"]["G"]["G"]; } Console.WriteLine("dicRef4:" + pr.EndsPerformanceRecord()); //--------------------------------------------------
↓↓↓
//-------------------------------------------------- pr.StartsPerformanceRecord(); dicRef = dicRef4["G"]["G"]["G"]; for (i = 0; i < num; i++) { strVal = dicRef["G"]; } Console.WriteLine("dicRef4性能対策実施版:" + pr.EndsPerformanceRecord()); //--------------------------------------------------
以下のように、性能が改善します。
dicRef: ExT:2996[msec], CT:3011[msec], KT:0[msec], UT:3011[msec] dicRef4: ExT:11754[msec], CT:11747[msec], KT:0[msec], UT:11747[msec] dicRef4性能対策実施版: ExT:3137[msec], CT:3089[msec], KT:0[msec], UT:3089[msec]
要素数が増えた場合、若干遅延します。
dicRef:要素数7 ExT:3003[msec], CT:2948[msec], KT:0[msec], UT:2948[msec] dicRefBigdata:要素数100万 ExT:3979[msec], CT:3994[msec], KT:0[msec], UT:3994[msec]
CSVデータをオブジェクト表現した際にサイズはどうなるか?
xxxxxxxxxx,xxxxxxxxxx,・・・,xxxxxxxxxx xxxxxxxxxx,xxxxxxxxxx,・・・,xxxxxxxxxx xxxxxxxxxx,xxxxxxxxxx,・・・,xxxxxxxxxx ・・・ xxxxxxxxxx,xxxxxxxxxx,・・・,xxxxxxxxxx
となりました。
45318record(10MB) End:ExT:1002[msec], CT:983[msec], KT:31[msec], UT:952[msec] 90636record(20MB) End:ExT:2095[msec], CT:2044[msec], KT:172[msec], UT:1872[msec]
class Program { static List<ClassRecord> ListClassRecord = new List<ClassRecord>(); static void Main(string[] args) { // CSVファイルを読み込むには?[2.0のみ、C#、VB] - @IT // http://www.atmarkit.co.jp/fdotnet/dotnettips/487csvparser/csvparser.html TextFieldParser parser = new TextFieldParser("CSV.csv", System.Text.Encoding.GetEncoding("utf-16")); int i = 0; PerformanceRecorder pr = new PerformanceRecorder(); pr.StartsPerformanceRecord(); using (parser) { parser.TextFieldType = FieldType.Delimited; parser.SetDelimiters(","); // 区切り文字はコンマ // parser.HasFieldsEnclosedInQuotes = false; // parser.TrimWhiteSpace = false; while (!parser.EndOfData) { i++; //// コンソールに出力 //Console.WriteLine(i.ToString()); // 1行読み込み string[] row = parser.ReadFields(); // クラスにロード Program.ListClassRecord.Add(new ClassRecord(row)); } } Console.WriteLine(i.ToString() +"record"); Console.WriteLine("End:" + pr.EndsPerformanceRecord()); Console.ReadKey(); } }
データサイズは単純に2倍になっているが、何処が肥大しているか?
が不明確であるので測定してみないと解らない。
また、フィールドのサイズ次第で増大する比率が変わってくる。
以下性能情報の取得に使用したマシンのスペック
------------------ System Information ------------------ Time of this report: 9/5/2014, 21:04:22 Machine name: ************ Operating System: Windows 7 Professional 32-bit (6.1, Build 7601) Service Pack 1 (7601.win7sp1_gdr.140303-2144) Language: Japanese (Regional Setting: Japanese) System Manufacturer: Hewlett-Packard System Model: HP ProBook 6570b BIOS: Default System BIOS Processor: Intel(R) Core(TM) i5-3210M CPU @ 2.50GHz (4 CPUs), ~2.5GHz Memory: 4096MB RAM Available OS Memory: 2954MB RAM Page File: 4026MB used, 1969MB available Windows Dir: C:\Windows DirectX Version: DirectX 11 DX Setup Parameters: Not found User DPI Setting: 120 DPI (125 percent) System DPI Setting: 120 DPI (125 percent) DWM DPI Scaling: Disabled DxDiag Version: 6.01.7601.17514 32bit Unicode