在调试与释放模式下Interlocked.Increment vs lock

时间:2013-12-22 14:01:01

标签: c# locking interlocked release-mode debug-mode

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

  

使用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);

我得到稳定的结果,锁定的近似值 2.4s ,Interlocked的 1.2s 。但是我惊讶地发现,在发布模式下运行此代码只能将Interlocked的值提高到大约 0.7s ,并且锁定时间保持不变。这是为什么?在处于释放模式时,Interlocked如何优化锁定?

1 个答案:

答案 0 :(得分:3)

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

   00FC27AD  call        7327A810 

发布版本:

   025F279D  lock inc    dword ptr [ebp-24h] 

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

优化只是没有比这更好。同样的优化不能应用于 lock 语句下面的Monitor.Enter()方法调用,它是一个非常重要的函数,它在CLR中实现,不能内联。它执行Interlocked.Increment()之外的许多事情,它允许操作系统在线程阻塞尝试获取监视器并维护等待线程的队列时重新调度。这对于确保良好的并发性非常重要,而不是在测试代码中,因为锁是完全无争议的。请注意与实际使用情况无关的综合基准测试。