zSy*_*sis 1 .net c# out-of-memory threadpool
我继续在下面的代码中得到一个内存不足的例外,我想知道是否有什么东西可以阻止这种情况发生.
private static List<string> MyIds { get; set; }
private static object LockObject { get; set; }
private static int Counter { get; set; }
private static readonly NumOfThreads = 5;
static void Main(string[] args)
{
try
{
Console.Clear();
LockObject = new object();
// Pull id's into memory (A list of around 1 million ids)
MyIds = _repository.GetIds();
for (int i = 0; i < NumOfThreads ; i++)
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), (object)i);
}
catch (Exception ex)
{
Console.WriteLine(ex.StackTrace);
}
}
public static void DoWork(Object stateInfo)
{
while (MyList.Count > 0)
{
lock (LockObject)
{
if (MyList.Count == 0)
return;
string id = MyList[0];
var record = _repository.GetRecord(id);
_repository.Add(record);
Counter++;
if (Counter % 100 == 0)
System.Console.WriteLine(DateTime.Now + " - Imported " + Counter.ToString() + " Records..");
MyList.RemoveAt(0);
}
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢你的帮助
您将从列表的开头删除,这将导致生成新列表并将旧列表复制到其中.如果您正在处理具有大量元素的列表,这将导致对大对象堆的破坏.
如果必须使用这种类型的设计,则反向移除项目,这将阻止复制List的基础数组,即从末尾向开头移除.
更好的设计是使用您使用Interlocked.Increment递增的计数器,并使用它来访问列表中的成员.您可以安全地执行此操作,因为您在创建列表后没有更改列表.
更新
从我的评论
您正在序列化对DoWork中所有代码的访问权限,因此使用多个线程毫无意义.
以下内容将避免从ID列表中删除的问题,并允许您可能从存储库中同时检索项目,从而利用这些额外的线程.我必须测量这一点 - 添加线程并不能保证性能的提高.
此外,如果您的"_repository"是一个集合,请确保将其大小调整为与ID列表大小相同的大小.当您添加项目时,这会阻止大量的中间数组复制.
private static int _counter = -1;
public static void DoWork(Object stateInfo)
{
int index;
while ((index = Interlocked.Increment(ref _counter)) < MyList.Count)
{
string id = MyList[index];
var record = _repository.GetRecord(id);
lock (LockObject)
{
_repository.Add(record);
}
if (index % 100 == 0)
Console.WriteLine(DateTime.Now + " - Imported " + (index + 1) + " Records..");
}
}
Run Code Online (Sandbox Code Playgroud)