C# 随着时间的推移,并行ForEach只消耗很少的处理能力
我运行了下面的代码,随着时间的推移(一到两个小时),我注意到遍历这些项所花费的时间越来越长。我正在做什么导致了这种情况的发生?如果是这样的话,我如何修复它C# 随着时间的推移,并行ForEach只消耗很少的处理能力,c#,.net,.net-4.0,parallel-processing,C#,.net,.net 4.0,Parallel Processing,我运行了下面的代码,随着时间的推移(一到两个小时),我注意到遍历这些项所花费的时间越来越长。我正在做什么导致了这种情况的发生?如果是这样的话,我如何修复它 int totalProcessed = 0; int totalRecords = MyList.Count(); Parallel.ForEach(Partitioner.Create(0, totalRecords), (range, loopState) => {
int totalProcessed = 0;
int totalRecords = MyList.Count();
Parallel.ForEach(Partitioner.Create(0, totalRecords), (range, loopState) =>
{
for (int index = range.Item1; index < range.Item2; index++)
{
DoStuff(MyList.ElementAt(index));
Interlocked.Increment(ref totalImported);
if (totalImported % 1000 == 0)
Log(String.Format("Processed {0} of {1} records",totalProcessed, totalRecords));
}
});
public void DoStuff(IEntity entity)
{
foreach (var client in Clients)
{
// Add entity to a db using EF
client.Add(entity);
}
}
inttotalprocessed=0;
int totalRecords=MyList.Count();
Parallel.ForEach(Partitioner.Create(0,totalRecords),(range,loopState)=>
{
对于(int index=range.Item1;index
感谢您的帮助
ElementAt
是一种非常缓慢的扩展方法,具有以下实现:
public static void T ElementAt(this IEnumerable<T> collection, int index)
{
int i = 0;
foreach(T e in collection)
{
if(i == index)
{
return e;
}
i++;
}
throw new IndexOutOfRangeException();
}
公共静态void T ElementAt(此IEnumerable集合,int索引)
{
int i=0;
foreach(集合中的T e)
{
如果(i==索引)
{
返回e;
}
i++;
}
抛出新的IndexOutOfRangeException();
}
很明显,索引越大,它的工作时间越长。您应该使用indexer
MyList[index]
而不是ElementAt
,正如@mace所指出的那样,使用ElementAt
存在性能问题。每次调用该函数时,迭代器都从MyList
的开头开始,跳过n个元素,直到到达所需的索引。随着指数位置越来越高,情况会越来越糟
如果您仍然需要对MyList
进行流式访问,可以通过使用跳过和获取来缓解性能问题。当您在MyList
中寻找一个职位时,仍然会有一些性能影响,但是Take
将确保您在到达那里后获得一批元素,而不是对每个元素都这样做
我还注意到,您使用的是分区样式foreach,但是您在整个范围内都在使用它。在下面的示例中,我使用批处理实现了分区样式
int totalRecords = MyList.Count();
int batchSize = 250;
Parallel.ForEach(Partitioner.Create(0, totalRecords, batchSize), range =>
{
foreach (var thing in MyList.Skip(range.Item1).Take(batchSize))
{
DoStuff(thing);
//logging and stuff...
}
});
更新
再次阅读该问题后,您可能会遇到以下问题:太多线程被用于可能是IO限制的问题,即网络,然后是DB\disk。我这样说就像你说CPU利用率很低一样,这让我觉得你在IO上被阻塞了,而且情况越来越糟
如果纯粹是ElementAt
,您仍然会看到高CPU利用率
配置MaxDegreeOfParallelism
以调整要使用的最大线程数:
const int BatchSize = 250;
int totalRecords = MyList.Count();
var partitioner = Partitioner.Create(0, totalRecords, BatchSize);
var options = new ParallelOptions { MaxDegreeOfParallelism = 2 };
Parallel.ForEach(partitioner, options, range =>
{
foreach (int thing in MyList.Skip(range.Item1).Take(BatchSize))
{
DoStuff(thing);
//logging and stuff...
}
});
你能发布一些关于“DoStuff”内部发生了什么的详细信息吗?好的,我已经编辑了我的代码,将“DoStuff”内部发生的事情包括在内。+1最近我看到一些人被ElementAt绊倒了。它应该附有健康警告。