我正在为一定数量的迭代运行模拟。在每次迭代结果发送后,服务器和一段时间之后服务器发送在下一次迭代中使用的更新数据。
代码(非常粗略地)看起来像这样:
for(var iteration=0;iteration<100;iteration++)
{
Parallel.For(0,50,i=>DoExpensiveWork(i));
SendResultsToServer(); //worker sends iteration results to server
//server gathers results from all workers,
//calculates update, then sends it back to workers
WaitForDataForNextIteration();
}
DoExpensiveWork正在使用ThreadLocal缓存(大多数只是每次迭代都重用的大型数组,以避免GC工作)。
ThreadLocal<MyCache> _cache;
private void DoExpensiveWork(int i)
{
var cache = _cache.Value;
DoSomeWorkUsingCache(cache);
}
以下是我遇到的问题:
随着时间的推移,_cache
增长缓慢(即_cache.Values.Count
)增加的值远高于我机器上的核心数量(我猜这意味着旧线程有时会被{{1下一次迭代使用新创建的线程,导致在ThreadPool
中创建其他条目。
这会导致“内存泄漏”。因为旧的缓存仍然保留在内存中,而无法访问。
当服务器花费大量时间发送更新时,_cache.Values
会在每次迭代时增长(在32核心机器上(2x16)_cache
增长如32,64,96等 - 增加32个新每次迭代的条目)。这只发生在服务器发送更新大约需要20秒时(如果需要15秒或更短时间,则不会发生这种情况)。
当工人等待更新时,这是否意味着_cache.Values
正在破坏线程?
我该怎样防止这种情况? 将最小/最大线程数设置为32无效
ThreadPool
我想要的主要是停止ThreadPool.SetMinThreads(32,1000);
ThreadPool.SetMaxThreads(32,1000);
缓存创建新条目,因此在我的情况下它不会超过32。
编辑:来自MSDN:当需求低时,线程池线程的实际数量可能会低于最小值。这可以解释为什么越来越多{{i> 1}}副本已创建。对此有何解决方法?