Bon*_*ver 6 .net c# 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);
});
Run Code Online (Sandbox Code Playgroud)
我原以为我会看到类似的东西:
......... 1
......... 2
......... 3
......... 4
......... 5
.........
.........
......... n
Run Code Online (Sandbox Code Playgroud)
但我得到的是16"......... 0"(这是因为我有一个双核四核计算机,有8个本机核心,但是启用了超线程,总共有16个核心).然后我将开始看到计数器在大多数情况下正常递增,但有时我会在Debug输出中看到重复或甚至三重计数器值.
使用Parallel.ForEach()计算循环迭代的最佳方法是什么?谢谢你的建议.
小智 14
Interlocked.Increment将返回递增的值.
所以,
int counter = 0;
Parallel.ForEach(urlList, (url, state) =>
{
// various code statments
var counterNow = Interloced.Increment( ref counter );
Debug.WriteLine(" ......... counter: " + counterNow);
});
Run Code Online (Sandbox Code Playgroud)
应该在递增时返回计数器值.
编辑,很久以后:
作为解释:
当您在多处理器/多核计算机上运行并具有多个应用程序线程时,您需要注意,您看到的变量值可能无法反映该变量的实际当前状态.这是因为每个CPU或芯片或套接字可能有许多单独的缓存,并且您的线程可以读取缓存的值(保存命中以读取主内存)
如果您只想读取由多个线程更新的值,则应使用Interlocked.Read()以保证您具有当前值counter.
这是因为Increment + WriteLine不是原子的.
可能是thread1递增counter,然后thread2再次递增它,然后两个线程以相同的值到达WriteLine部分counter.