根据我的理解,Parallel.ForeachAsync 调用中的委托会同时执行多次。
如果该委托操作的变量不是该委托的本地变量怎么办?
假设我在委托中增加了一个静态计数器。我需要通过互斥锁或其他东西来保护计数器吗?
Parallel
不是魔法。您需要使用所有常用机制来防止访问共享状态和最坏情况,如果无法避免,请同步它。
当然,如果你只是在
Parallel
中进行同步,你很快就会发现它完全毫无价值,以占用更多 CPU 为代价,只能给你带来更好的结果(甚至更糟)。这个想法是将工作分解为互不影响的工作 - 例如,通过确保您正在操作的集合已经拥有它所需的所有输入,并且只将输出生成到输出集合中。然后Parallel
可以尽最大努力提高效率。但当然,只有当批次足够大以支付同步成本时,它才有效。
请记住,
Parallel
有很多小怪癖,因此请进行概要分析、阅读并非常小心地了解正在发生的事情。这不是魔法。
Parallel
并行执行多项工作。如果工作共享非线程安全资源,则该资源可能会被损坏。那么资源需要被保护。
示例:
var values = Enumerable.Range(0, 1000);
int counter = 0;
int safeCounter = 0;
await Parallel.ForEachAsync(values, async (value, token) =>
{
await Task.Yield(); // Simulate some work
counter++;
Interlocked.Increment(ref safeCounter);
});
Console.WriteLine(counter); // 991 (can vary)
Console.WriteLine(safeCounter); // 1000 (as expected)
假设我在委托中增加了一个静态计数器。我需要通过互斥锁或其他东西来保护计数器吗?
是的,你必须使用一些同步机制来保护你的非线程安全共享状态,比如
lock
。 body
委托在 ThreadPool
上调用,并遵守 MaxDegreeOfParallelism
政策。 Parallel.ForEachAsync
的设计并非只考虑异步并发,而没有并行性。为了防止并行性而又不无意中阻止并发性,您必须跨过困境。