我目前正在调查应用程序中的一些严重性能下降。
性能下降是一种奇怪的现象-连续几次迭代的工作速度非常快,但是一次迭代需要花费更多的时间才能完成。 该应用程序可以处理图形,因此看起来很烦人。
请看下面的代码。
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
的方式有问题,但是我不知道到底是哪里出了问题。
答案 0 :(得分:2)
如果您在测得的部分之前致电GC.Collect()
,该问题通常会消失。看来您在垃圾回收方面遇到了问题。尝试减少垃圾产生量,减少废弃结构的复杂度。这是重新设计解决方案的一种方法:
var results = new HashSet<(int X, int Y)>();
object resultLockObj = new object();
var rng = new Random(1);
var sw = new Stopwatch();
while (true)
{
results.Clear();
sw.Restart();
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((i, j * j));
}
if (entry.Count == 0)
{
entry = null;
}
if (entry != null)
{
lock (resultLockObj)
{
foreach (var x in entry)
{
results.Add(x);
}
}
}
});
var time = sw.ElapsedMilliseconds;
Console.WriteLine($"Result count: {results.Count:00000}, time: {time:000}");
//Thread.Sleep(1000);
}
编辑
我做了些微小的改变。 (j, j * j)
现在为(i, j * j)
,因此结果中没有重复项,并且消除了它们也不会提高性能。而且,不是每次我都清除它时都创建HashSet(这是您无法使用ConcurrentBag进行的操作),以进一步减少垃圾产生。您是对的,元组是一个值,但是问题出在其他地方。当您将列表添加到另一个结构中时,您将保持指向它们的指针,并且将其删除会更加困难。最好使用简单的短期结构。而且,如果您可以回收它们,那显然是最好的选择。
答案 1 :(得分:1)
您的问题是由GC挂起所有线程以执行其不可思议的操作引起的(我对此进行了分析,结果非常明显)。这样做的原因是,您要分配很多<th>
<input class="form-control partQuantity partQtyInput" data-outrightp="$12.57" type="text" placeholder="1">
</th>
<td>000-126042</td>
<td>Nipple Filter</td>
<td>$12.57</td>
<td class="extendedPrice">$12.57</td>
和List
和ConcurrentBag
(分配在列表中,所以最终还是放在堆上)的地狱,然后抛弃下一个循环。 ValueTuple
超出范围,其中也包含所有ConcurrentBag
。对于List
也是如此。
因此,您要消除所有可以执行的分配,例如通过预先在堆上分配所需的存储空间,从而避免了新的实例化。
以下代码应使您了解如何实现此目标-语义上可能不是100%等效的,但我假设您无论如何都无法将其复制/粘贴到您的解决方案中,因为它基于简化示例:
ValueTuple