C#のDictionaryはマルチスレッドに弱く、Add()をマルチスレッドで繰り返すと5万件程度で「IndexOutOfRangeException」が発生します。
List<T>ならマルチスレッドでAdd()を繰り返しても、1500万件程度まで「OutOfMemoryException」は発生しませんでした。
DictionaryのAdd()をlockで囲み、その部分だけシングルスレッドにすれば解消されますが、.Net2.0以上にはList<T>という、マルチスレッドに強く使い勝手も良い機能があるので、初めからDictionaryを使わずにList<T>で統一するのが望ましいです。
以下は実験した結果。
実験に使用したソース => Src実証実験をダウンロード
■実証実験1(シングルスレッド)
DictionaryをシングルスレッドでAdd()し、「Key、Value」の文字数を横方向に爆発させた場合、「OutOfMemoryException」になる。
a、コード
Dictionary<string, string> dict = new Dictionary<string, string>();
string Key = "";
string Value = "";
while (true)
{
Key += "a";
Value += "b";
dict.Add(Key, Value);
}
b、結果
■実証実験2(シングルスレッド)
DictionaryをシングルスレッドでAdd()し、「Key、Value」の要素数を縦方向に爆発させた場合、1000万件程度で「OutOfMemoryException」になる。
a、コード
Dictionary<string, string> dict = new Dictionary<string, string>();
long Key = 0;
long Value = 0;
while (true)
{
dict.Add(Key.ToString(), Value.ToString());
Key++;
Value++;
}
b、結果
■実証実験3(マルチスレッド)
DictionaryをマルチスレッドでAdd()し、「Key、Value」の要素数を縦方向に爆発させた場合、5万件程度で「IndexOutOfRangeException」になる。
a、コード
public class C実験3
{
Dictionary<string, string> dict = new Dictionary<string, string>();
public void DictionaryAdd(object id)
{
long Key = 0;
long Value = 0;
while (true)
{
dict.Add((string)id + Key.ToString(), Value.ToString());
Key++;
Value++;
}
}
}
private void 実証実験3()
{
var 実験3 = new C実験3();
var t1 = new Thread(new ParameterizedThreadStart(実験3.DictionaryAdd));
var t2 = new Thread(new ParameterizedThreadStart(実験3.DictionaryAdd));
var t3 = new Thread(new ParameterizedThreadStart(実験3.DictionaryAdd));
t1.Start("A");
t2.Start("B");
t3.Start("C");
}
b、結果
■実証実験4(マルチスレッド lock有り)
DictionaryをマルチスレッドでAdd()する際、Add()だけlockさせ、「Key、Value」の要素数を縦方向に爆発させた場合、1000万件程度で「OutOfMemoryException」になる。
a、コード
public class C実験4
{
Dictionary<string, string> dict = new Dictionary<string, string>();
public void DictionaryAdd(object id)
{
long Key = 0;
long Value = 0;
while (true)
{
lock (dict)
{
dict.Add((string)id + Key.ToString(), Value.ToString());
}
Key++;
Value++;
}
}
}
private void 実証実験4()
{
var 実験4 = new C実験4();
var t1 = new Thread(new ParameterizedThreadStart(実験4.DictionaryAdd));
var t2 = new Thread(new ParameterizedThreadStart(実験4.DictionaryAdd));
var t3 = new Thread(new ParameterizedThreadStart(実験4.DictionaryAdd));
t1.Start("A");
t2.Start("B");
t3.Start("C");
}
b、結果
■実証実験5(List<T> マルチスレッド)
List<T>をマルチスレッドでAdd()し、「Key、Value」の要素数を縦方向に爆発させた場合、1500万件程度で「OutOfMemoryException」になる。
a、コード
public class C実験5
{
private class StrData
{
public string str1;
public string str2;
}
List dict = new List();
public void DictionaryAdd(object ThreadId)
{
long Key = 0;
long Value = 0;
while (true)
{
dict.Add(new StrData { str1 = (string)ThreadId + Key.ToString(), str2 = Value.ToString() });
Key++;
Value++;
}
}
}
private void 実証実験5()
{
var 実験5 = new C実験5();
var t1 = new Thread(new ParameterizedThreadStart(実験5.DictionaryAdd));
var t2 = new Thread(new ParameterizedThreadStart(実験5.DictionaryAdd));
var t3 = new Thread(new ParameterizedThreadStart(実験5.DictionaryAdd));
t1.Start("A");
t2.Start("B");
t3.Start("C");
}
b、結果
最近のコメント