お久しぶりです、エンジニアのMasashiです。
今回は、DataGridViewのデータ表示速度を比較したいと思います。
DataGridView(Windows Forms)を使用した新規開発はあまり多くはないかもしれませんが、
既存システムの改修等で触れる機会があるのではないでしょうか?
速度面の問題が合わせて改修要件に入ってくることもあるため
今回はDataGridViewにデータを表示させる際の速度を3つの方法から検証してみたいと思います。
測定までの流れ
今回測定を行うのは、10行・10,000列のDataGridViewに単純な文字データを表示するまでに要した時間になります。
比較対象としてRows.Addで1行・1セルずつデータを追加するパターン(非バインド)、DataTableのデータをバインドするパターン、自作クラス(Model)をバインドするパターンの3つの場合について検証しています。
測定環境
- CPU:Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz (4 CPUs), ~2.9GHz
- メモリ:16GB
- Visual Studio 2015
対象データ
- DataGridViewの行数:10
- DataGridViewの列数:10,000
- 各セルに書き込む文字:Rows_(列数):Cols_(行数)
測定対象
- Rows.Addで1行・1セルずつデータを追加(非バインド)
- DataTableのデータをバインド
- 自作クラス(Model)をバインド
テストコード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
using System; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Windows.Forms; namespace DataGridViewSpeedTest { public partial class Form1 : Form { private const int LoopCount = 10; private const int ColumnCount = 10; private const int RowsCount = 10000; public Form1() { InitializeComponent(); } // Rows.Addボタンクリック時 private void btnRowsAdd_Click(object sender, EventArgs e) { // 10回試行した時の秒数を保持する変数 var totalMili = 0.0d; for(var i = 0; i < LoopCount; i++) { // DataGridViewのデータをクリア dgvSpeedTest.DataSource = null; dgvSpeedTest.Rows.Clear(); dgvSpeedTest.Columns.Clear(); // 計測中はボタンをいじれないように設定 btnRowsAdd.Enabled = false; var sw = Stopwatch.StartNew(); // start try { // Layoutの実行を保留する dgvSpeedTest.SuspendLayout(); // DataGridViewカラム追加 for (int col = 0; col < ColumnCount; col++) { dgvSpeedTest.Columns.Add("Col_" + col, "Col_" + col.ToString()); } // 行追加 for (int row = 0; row < RowsCount; row++) { dgvSpeedTest.Rows.Add(); // 1セルずつ for (int col = 0; col < ColumnCount; col++) { dgvSpeedTest.Rows[dgvSpeedTest.RowCount - 1].Cells[col].Value = "Rows_" + row + ":Cols_" + col; } } } finally { // 保留中のLayoutを再開する dgvSpeedTest.ResumeLayout(); } sw.Stop(); totalMili += sw.Elapsed.TotalMilliseconds; } // 10回試行した時の平均を算出 txtRowsAdd.Text = (totalMili / LoopCount).ToString(); btnRowsAdd.Enabled = true; } // DataTableボタンクリック時 private void btnDataTable_Click(object sender, EventArgs e) { // 10回試行した時の秒数を保持する変数 var totalMili = 0.0d; for(var i = 0; i < LoopCount; i++) { // DataGridViewのデータをクリア dgvSpeedTest.DataSource = null; dgvSpeedTest.Rows.Clear(); dgvSpeedTest.Columns.Clear(); // 計測中はボタンをいじれないように設定 btnDataTable.Enabled = false; var sw = Stopwatch.StartNew(); var dt = new DataTable(); try { // Layoutの実行を保留する dgvSpeedTest.SuspendLayout(); // DataColumnの追加 for (int col = 0; col < ColumnCount; col++) { dt.Columns.Add("Col_" + col.ToString()); } // 行データの追加 for (int row = 0; row < RowsCount; row++) { var dr = dt.NewRow(); // 表列に対応するデータの格納 for (int col = 0; col < 10; col++) { dr[col] = "Rows_" + row + ":Cols_" + col; } dt.Rows.Add(dr); } // DataTableをDataGridViewにバインド dgvSpeedTest.DataSource = dt; } finally { // 保留中のLayoutを再開する dgvSpeedTest.ResumeLayout(); } sw.Stop(); totalMili += sw.Elapsed.TotalMilliseconds; } // 10回試行した時の平均を算出 txtDataTable.Text = (totalMili / LoopCount).ToString(); btnDataTable.Enabled = true; } // Classボタンクリック時 private void btnClass_Click(object sender, EventArgs e) { // 10回試行した時の秒数を保持する変数 var totalMili = 0.0d; for(var i = 0; i < LoopCount; i++) { // DataGridViewのデータをクリア dgvSpeedTest.DataSource = null; dgvSpeedTest.Rows.Clear(); dgvSpeedTest.Columns.Clear(); // 計測中はボタンをいじれないように設定 btnClass.Enabled = false; var sw = Stopwatch.StartNew(); var data = new List<TestModel>(); try { // Layoutの実行を保留する dgvSpeedTest.SuspendLayout(); // DataGridViewのカラム追加 for (int col = 0; col < ColumnCount; col++) { var column = new DataGridViewTextBoxColumn(); column.HeaderText = "Col_" + col; column.DataPropertyName = "Col_" + col; dgvSpeedTest.Columns.Add(column); } // DataRowを追加 for (int row = 0; row < RowsCount; row++) { var tm = new TestModel(); tm.Col_0 = "Rows_" + row + ":Cols_0"; tm.Col_1 = "Rows_" + row + ":Cols_1"; tm.Col_2 = "Rows_" + row + ":Cols_2"; tm.Col_3 = "Rows_" + row + ":Cols_3"; tm.Col_4 = "Rows_" + row + ":Cols_4"; tm.Col_5 = "Rows_" + row + ":Cols_5"; tm.Col_6 = "Rows_" + row + ":Cols_6"; tm.Col_7 = "Rows_" + row + ":Cols_7"; tm.Col_8 = "Rows_" + row + ":Cols_8"; tm.Col_9 = "Rows_" + row + ":Cols_9"; data.Add(tm); } // テストModelをDataGridViewにバインド dgvSpeedTest.DataSource = data; } finally { // 保留中のLayoutを再開する dgvSpeedTest.ResumeLayout(); } sw.Stop(); totalMili += sw.Elapsed.TotalMilliseconds; } txtClass.Text = (totalMili / LoopCount).ToString(); btnClass.Enabled = true; } } } namespace DataGridViewSpeedTest { class TestModel { public string Col_0 { get; set; } public string Col_1 { get; set; } public string Col_2 { get; set; } public string Col_3 { get; set; } public string Col_4 { get; set; } public string Col_5 { get; set; } public string Col_6 { get; set; } public string Col_7 { get; set; } public string Col_8 { get; set; } public string Col_9 { get; set; } } } |
DataGridViewデータ表示の測定結果
10回試行した結果の平均値が下記になっています。小数点第1位で四捨五入しています。
計測項目 | 計測時間(ms) |
---|---|
Rows.Addで1行・1セルずつデータを追加(非バインド) | 3316 |
DataTableのデータをバインド | 129 |
自作クラス(Model)をバインド | 59 |
上記の結果を比較してみると自作クラスをバインドしたパターンの速度が圧倒的に速い結果になりました。
1行・1セルずつデータを追加するパターンは単純にデータ量も多いため非常に時間がかかる結果になっています。
DataTableをバインドしたパターンは、DataTableに関する処理が重いために
同様のバインドでも自作クラスとの差が生まれたと考えられます。
DataGridViewデータ表示速度のまとめ
既存システムの改修や新規開発を行う上でDataGridViewを触る機会がある場合は、
可能ならば自作クラスをバインドすることで、非常に高速な処理が行えます。
しかし、DataGridViewに表示するデータはDBから取得したデータが多いため
便利なDataTableを使っている、または使いたいパターンも多くあると思います。
速度差は倍以上違いますが、ミリ秒の世界での話なので普段はあまり気にせずDataTableをバインドして
問題ないかと考えられます。
表示までに求められる時間が非常にシビアな場合は、自作クラスをバインドしてみてはいかがでしょうか。
この記事が少しでも皆さんのお役に立てば幸いです。