【发布时间】:2019-03-06 12:07:05
【问题描述】:
我目前正在调查应用程序中的一些严重性能下降情况。
性能下降是一种奇怪的类型 - 连续几次迭代工作得非常快,但是有一个迭代需要更多时间才能完成。 这个应用程序使用图形,所以看起来很烦人。
请看下面的代码。
while (true)
{
var rng = new Random(1);
var concurrenBag = new ConcurrentBag<ICollection<(int X, int Y)>>();
Parallel.For(0, 20000, i =>
{
var entry = new List<(int X, int Y)>(); // essentially, this is what's going on:
var r = rng.Next(0, 3); // around 20k handlers return coordinates of pixels to redraw
for (var j = 0; j < r; j++) // sometimes there are null entries, sometimes 1, more often 2
{ // all entries are added to concurrent bag
entry.Add((j, j * j));
}
if (entry.Count == 0)
entry = null;
concurrenBag.Add(entry);
});
var sw = Stopwatch.StartNew();
var results = concurrenBag.ToList().AsParallel().Where(x => x != null).SelectMany(x => x).Distinct().ToList(); // this is where severe performance drops occur from time to time
var time = sw.ElapsedMilliseconds;
Console.WriteLine($"CB count: {concurrenBag.Count:00000}, result count: {results.Count:00}, time: {time:000}");
//Thread.Sleep(1000);
}
此代码产生以下结果:
CB count: 20000, result count: 02, time: 032 <- this is fine, initialization and stuff
CB count: 20000, result count: 02, time: 004
CB count: 20000, result count: 02, time: 014 <- this is not fine
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 004
CB count: 20000, result count: 02, time: 004
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 015 <- every couple of frames it happens again
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 019
CB count: 20000, result count: 02, time: 004
CB count: 20000, result count: 02, time: 004
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 014
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 004
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 008
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 004
CB count: 20000, result count: 02, time: 011
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 003
CB count: 20000, result count: 02, time: 004
我相信你明白了。在实际应用中,每次“好的”迭代大约需要 10-15 毫秒,而那些缓慢的迭代每 6-8 次迭代就会发生一次,最多需要 150 毫秒或类似的时间。
老实说,我认为我的业务逻辑出了点问题,但是您可以运行上面的示例并获得完全相同的结果。我现在猜测是我使用Parallel.For、AsParallel() 或ConcurrentBag 的方式有问题,但我不知道到底出了什么问题。
【问题讨论】:
-
检查了垃圾收集器?
-
@TomTom 不,我没有;D
-
您究竟想在实际应用程序中实现什么?我有一种感觉,你想在这里有一个并行的生产者/消费者模式,但最终首先收集了大量数据,然后再进行处理。这会给你 GC 压力......第二个循环是否应该不与第一个循环并行运行并在添加项目时对其进行处理?这将使您的内存占用更少。
-
@DmitryVolkov a ConcurrentBag 不相当于并发集合。它适用于线程本地存储,这意味着您在访问由不同线程创建的任何存储桶时会付出代价。
-
附带说明,
ConcurrentBag<T>是一个very specialized 集合。在这种情况下,ConcurrentQueue<T>会更好地为您服务,因为它保留了入队项目的顺序(而且它也会稍微快一些)。
标签: c# performance linq task-parallel-library plinq