c# - Interlocked.Increment() 没有按照我在任务并行库中期望的方式工作

标签 c# .net parallel-processing

我有一个 Parallel.ForEach() 循环,它获取一个 URL 列表并下载每个 URL 以进行一些额外的处理。在我的循环之外,我已经声明了一个循环计数器变量,并且在循环体内我使用了 Interlocked.Increment() 认为这将是保持“线程安全”的最佳方式,以便在执行每个循环交互时增加计数。

int counter = 0;

Parallel.ForEach(urlList, (url, state) =>
{
    // various code statments

    Interlocked.Increment( ref counter );

    Debug.WriteLine(" ......... counter: " + counter);
});

我原以为我会看到类似的东西:

 ......... 1
 ......... 2
 ......... 3
 ......... 4
 ......... 5
 ......... 
 ......... 
 ......... n

但我得到的是 16 "......... 0"(这是因为我有一台双四核计算机,有 8 个 native 内核,但启用了超线程,总共有 16 个内核).然后我会开始看到计数器在大多数情况下正常递增,但有时我会在调试输出中看到重复甚至三次计数器值。

使用 Parallel.ForEach() 计算循环迭代次数的最佳方法是什么?感谢您的任何建议。

最佳答案

Interlocked.Increment 将返回您增加的值。

所以,

int counter = 0;

Parallel.ForEach(urlList, (url, state) =>
{
    // various code statments

    var counterNow = Interlocked.Increment( ref counter );

    Debug.WriteLine(" ......... counter: " + counterNow);
});

应该在递增时返回计数器值。

当您在多处理器/多核机器上运行并拥有多个应用程序线程时,您需要注意,您看到的变量值可能并不反射(reflect)该变量的实际当前状态。 这是因为可能有很多单独的缓存,对于每个 CPU 或 die 或 socket,您的线程可以读取缓存的值(节省一次读取主内存的命中)

如果您只想读取一个由多个线程更新的值,您应该使用 Interlocked.Read() 来保证您拥有 counter 的当前值。

关于c# - Interlocked.Increment() 没有按照我在任务并行库中期望的方式工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4772757/

相关文章:

c# - 性能测试秒表

c# - 为什么这个循环再做一次迭代?

c# - IDisposable 在方法中创建并返回

c# - 替换 If Else 唯一条件嵌套语句

.NET 库访问 COM 端口?

c# - 只使用 async Task 和 Task 有什么区别?

c# - IMemoryCache 的依赖注入(inject)问题

.net - 编译器失败,错误代码为128

c - 为什么这段使用openmp计算Pi值的代码每次给出的答案(最后几个 float )都略有不同?

c# - 是否可以始终使用 Task 强制一个新线程?