Interlocked.Increment vs lock in debug vs release mode

Ond*_*cek 3 c# locking interlocked release-mode debug-mode

我正在测试我的计算机架构上的行为Interlocked.Incrementlock行为,因为我阅读了本文中的以下几行。

正如用 Interlocked.Increment 重写的那样,该方法应该执行得更快,至少在某些架构上是这样。

使用以下代码,我确信在我的项目中检查锁是值得的。

var watch = new Stopwatch();
var locker = new object();
int counter = 0;

watch.Start();
for (int i = 0; i < 100000000; i++)
{
    lock (locker)
    {
        counter++;
    }
}
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalSeconds);

watch.Reset();
counter = 0;

watch.Start();
for (int i = 0; i < 100000000; i++)
{
    Interlocked.Increment(ref counter);
}
watch.Stop();
Console.WriteLine(watch.Elapsed.TotalSeconds);
Run Code Online (Sandbox Code Playgroud)

我越来越有近似值稳定的结果2.4S用于锁定和1.2秒的互锁。然而,我惊讶地发现在发布模式下运行此代码仅将 Interlocked 的值提高到大约0.7 秒,并且锁定时间保持不变。这是为什么?在释放模式下锁定不是互锁时如何优化互锁?

Han*_*ant 5

您必须查看生成的机器码才能看到差异,Debug + Windows + Disassembly。Interlocked.Increment() 调用的调试版本:

   00FC27AD  call        7327A810 
Run Code Online (Sandbox Code Playgroud)

发布构建版本:

   025F279D  lock inc    dword ptr [ebp-24h] 
Run Code Online (Sandbox Code Playgroud)

或者换句话说,抖动优化器在 Release 版本中变得非常聪明,并将对辅助函数的调用替换为单个机器指令。

没有比这更好的优化了。相同的优化不能应用于lock语句下面的 Monitor.Enter() 方法调用,它是在 CLR 中实现的一个非常重要的函数,不能内联。除了 Interlocked.Increment() 之外,它还可以做很多事情,它允许操作系统重新安排线程何时尝试获取监视器并维护等待线程队列。这对于确保良好的并发性非常重要,只是不在您的测试代码中,因为锁完全没有争议。谨防不接近实际使用情况的综合基准。