Interlocked.Increment在并行foreach中正确计数线程数。

huangapple go评论82阅读模式
英文:

does Interlocked.Increment count right the number of threads into parallel foreach

问题

我只想计算在并行foreach中运行的线程数。

我刚刚写了这段代码,并期望threads.Count等于threadsCount,但实际上不是这样。threadsCount变量始终大于threads.Count。为什么?

还有,为什么我应该使用Interlocked而不是像HashSet这样的标准集合?

int threadsCount = 0;
HashSet<int> threads = new HashSet<int>();

Parallel.ForEach(productConfig.Documenti.Keys, new ParallelOptions { MaxDegreeOfParallelism = MaxNumOfThreads }, key =>
{
  int progress = Interlocked.Increment(ref threadsCount);
  threads.Add(System.Threading.Thread.CurrentThread.ManagedThreadId);
});
英文:

I just want to count the numeber of threads runnuing into foreach parallel.

i just wrote this code and expect the threads.count is equl to threadsCount is the same, but it is not. the variable threadsCount is always greater than threads.Count. Why?

Also why should i use Interlocked instead of a standard collection like HashSet?

int threadsCount = 0;
HashSet&lt;int&gt; threads = new HashSet&lt;int&gt;();

Parallel.ForEach(productConfig.Documenti.Keys, new ParallelOptions { MaxDegreeOfParallelism = MaxNumOfThreads }, key =&gt;
{
  int progress = Interlocked.Increment(ref threadsCount);
  threads.Add(System.Threading.Thread.CurrentThread.ManagedThreadId);
});

答案1

得分: 1

你的互锁计数器在计算键,而不是线程。回调将在每个 上调用,这些回调将在选择使用的线程数量之间分配,最多不超过 MaxDegreeOfParallelism。这不是每个键一个线程 - 因为线程非常昂贵,通常并没有使用比CPU核心更多的线程并行处理的必要。通常,它只是在一些线程池线程之间共享负载。因此,是的,我们预期您的互锁计数器最终会达到与 productConfig.Documenti.Keys.Count 相同的数量,而 threads.Count 最终会成为实际使用的线程数。我们预期 threads.Count 通常会远少于您的计数器,除非只有一两个键。

注意:HashSet&lt;T&gt; 不是线程安全的,因此当前的代码可能会出现严重错误 - 您需要使用并发或同步数据存储才能可靠地使其工作。

还有为什么我要使用互锁而不是像 HashSet 这样的标准集合?

为什么要使用其中一个?你为什么关心使用了多少线程?以及为什么要计算您自己提供的键的数量?

英文:

Your interlocked counter is counting keys, not threads. The callback will be invoked on every key, and those callbacks will be spread between whatever number of threads it chooses to use, at most MaxDegreeOfParallelism. It is not a thread per key - as threads are very expensive, and there's usually not much point parallelising with more threads than you have CPU cores. Usually, it simply shares the load between some number of pool threads. So yes, we would expect that your interlocked counter ends up at the same number as productConfig.Documenti.Keys.Count, and threads.Count ends up as being whatever number of threads actually got used. We would expect that threads.Count is usually much less than your counter, unless there are only one or two keys.

Note: HashSet&lt;T&gt; is not thread-safe, so right now this code could break horribly - you would need to use a concurrent or synchronized data store for that to work reliably.

> Also why should i use Interlocked instead of a standard collection like HashSet?

Why should you use either? why do you care how many threads were used? and why are you counting the keys that you yourself provided?

huangapple
  • 本文由 发表于 2023年2月23日 23:13:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75546726.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定