【发布时间】:2021-09-19 13:48:16
【问题描述】:
我正在为我的任务使用Parallel 类,并且需要实现一个进度百分比计数器。尝试组合不同的锁,但要么性能很慢,要么结果如屏幕截图所示。
这是一个有效但速度慢的代码示例。因为我挡住了整个部分。
Parallel.ForEach(bossUsers, StandardParallelOptions(), (user) =>
{
logger.Trace($"Sync new user {user.PID}.");
while (queue.Count >= MaxDegreeOfParallelism)
{
Thread.Sleep(1);
}
queue.Enqueue(user);
CreateOrUpdateUserAsync(
cardRepository,
dbScope,
user,
logger,
cancellationToken)
.ConfigureAwait(false);
lock (locker)
{
var current = (int)(((progress) / (decimal)bossUsers.Count) * 100);
if (current > 0 && current % 10 == 0)
{
if (last != current)
logger.Info($"Progress: {current}%");
last = current;
}
}
logger.Trace($"Sync user {user.PID} complete.");
});
如果我移除锁,我会得到很多类似的行
请告知如何进行锁定,以免严重减慢服务速度。谢谢!
【问题讨论】:
-
某事正在增加
progress。为什么它不做日志记录? -
but either get very slow performance不加锁有多快?带锁的速度有多快? 具体。 -
是的,通过 Interlocked.Increment(ref progress) 在 CreateOrUpdateUserAsync 方法中增加进度
-
您不需要锁定。你知道集合的大小。你知道递增的进度。您可以根据当前进度指示器和指示器计算百分比 - 1。如果以前的值为 59%,而新值为 60%(即 10 的倍数),那么万岁 - 您需要记录。 不需要锁定。
-
CreateOrUpdateUserAsyncI/O 还是 CPU 受限?如果是前者,那么Parallel.ForEach不是你的朋友,因为它是为 CPU 绑定操作而设计的。如果您查看overloads,您会发现它们都没有预期到异步函数。在 .NET 6 中会有一个Parallel.ForeachAsync,它也可以用于 I/O 绑定操作。
标签: c# thread-safety parallel.foreach