在不同平台上,对于int和long类型,Interlocked.Increment(ref x)
和x++
哪个更快或更慢?
在不同平台上,对于int和long类型,Interlocked.Increment(ref x)
和x++
哪个更快或更慢?
由于Interlocked.Increment强制操作以原子方式进行,并且充当内存屏障,消除了处理器在指令周围重新排序内存访问的能力,因此它速度较慢。
当您想要在线程之间共享的状态上执行原子操作时,应该使用Interlocked.Increment - 它不是x++的完全替代品。
根据我们的经验,在Windows上使用InterlockedIncrement()等函数会产生相当大的影响。在一个样例中,我们能够消除互锁并使用++/--代替。这单一操作就将运行时间从140秒减少到110秒。我的分析是,互锁强制进行内存往返(否则其他核心如何看到它?)。L1缓存读/写约为10个时钟周期,但内存读/写需要更多的时间,约为100个时钟周期。
在这个样例中,我估计增量/减量操作的数量约为10亿次。因此,在2Ghz的CPU上,++/--需要约5秒钟,而互锁需要约50秒钟。将差异分散到几个线程中,就接近30秒了。
Increment
调用不能比简单的递增运算符应用更快。如果是这样的话,那么编译器对递增运算符的实现将在内部调用Increment
,它们将执行相同的操作。Increment
。(如果他们没有全部合作,则实际上并没有帮助)。虽然速度较慢,但这是我所知道的实现标量变量线程安全的最有效通用方法。
volatile
在标量上的表现更佳,但缺点是需要使用良好的编程实践来发挥其作用。 - Abel++
运算符时,即使加上 volatile
关键字,仍然不是原子操作 / 不是线程安全的。而使用 Interlocked.Increment
(或者 lock
和 ++
)则是线程安全的。此外,在这两种有效的线程安全方法中,使用 volatile
是不必要的。 - user2864740由于它必须执行CPU总线锁定而不是仅更新寄存器,因此它将始终较慢。但是,现代CPU实现了接近寄存器性能,因此即使在实时处理中也可以忽略不计。
我的性能测试:
volatile(易失性变量):65,174,400
lock(锁):62,428,600
interlocked(交互式):113,248,900
TimeSpan span = TimeSpan.FromSeconds(5);
object syncRoot = new object();
long test = long.MinValue;
Do(span, "volatile", () => {
long r = Thread.VolatileRead(ref test);
r++;
Thread.VolatileWrite(ref test, r);
});
Do(span, "lock", () =>
{
lock (syncRoot)
{
test++;
}
});
Do(span, "interlocked", () =>
{
Interlocked.Increment(ref test);
});
VolatileRead
和 VolatileWrite
,会不会让你面临与 lock
和 Interlocked.Increment
可以避免的相同竞争条件呢? - ta.speot.is