c# lock的性能损耗到底有多大 lock和无锁操作性能对比

来源:这里教程网 时间:2026-02-21 17:37:51 作者:

lock 的性能损耗在什么量级?

在无竞争(即几乎没线程抢锁)时,

lock
的开销极低——现代 .NET(6+)会先自旋几轮,不进内核,耗时通常

典型对比(1000 万次计数操作,单核模拟竞争):

Interlocked.Increment(ref x)
:约 80–120 ms
lock(obj) { x++; }
:约 450–900 ms(取决于争抢强度)
Mutex.WaitOne()
:常超 3000 ms(跨进程开销大)

什么时候该换 Interlocked 而不是 lock?

只要你的临界区只干一件事:读/写/更新一个字段(int、bool、引用等),且逻辑不依赖其他变量或状态判断,就该用

Interlocked

常见误用场景:

lock
保护一个
if (count > 0) count--;
—— 这其实是「读-判-改」三步,
lock
正确但过重
✅ 改成
if (Interlocked.Decrement(ref count) >= 0) { /* 成功减了 */ }
—— 原子 CAS,无锁,更快更安全
✅ 计数器、开关标志、引用替换(
Interlocked.Exchange
)、初始化单例(
Interlocked.CompareExchange
)都适合

lock 真正的代价不在“加锁”,而在“阻塞”

lock
本身不慢,慢的是线程被迫挂起 + 唤醒带来的上下文切换。一个被阻塞的线程要经历:用户态 → 内核态 → 睡眠队列 → 调度唤醒 → 用户态,这过程至少耗费几十微秒,还吃 CPU 调度资源。

实操建议:

避免在
lock
块里做 I/O、网络调用、
Thread.Sleep
、复杂计算——这些会让锁持有时间变长,放大争抢
不要用
string
或装箱值类型(如
(object)123
)当锁对象——每次都是新对象,根本锁不住
优先用
private static readonly object _lock = new object();
,别用
this
或 public 成员,防外部干扰

读多写少?别硬扛 lock,试试 ReaderWriterLockSlim

如果你的字段被读取几千次,只写几次(比如配置缓存、设备状态),

lock
就是瓶颈:所有读操作也得排队。

换成

ReaderWriterLockSlim
后,读可以并发,写才互斥:

private readonly ReaderWriterLockSlim _rwLock = new ReaderWriterLockSlim();
private int _value;
<p>public int Value
{
get
{
_rwLock.EnterReadLock();
try { return _value; }
finally { _rwLock.ExitReadLock(); }
}
set
{
_rwLock.EnterWriteLock();
try { _value = value; }
finally { _rwLock.ExitWriteLock(); }
}
}

注意:它比

lock
略重(多一层状态管理),但读并发提升明显;若读写比例 Interlocked 或
volatile
+ 规则约束。

真正容易被忽略的一点:锁的粒度永远比锁的种类更重要。哪怕你用了

Interlocked
,如果把它套在一个高频循环里反复调用,也比把几个相关字段打包进一个轻量
lock
块更慢——因为函数调用和内存屏障本身也有成本。

相关推荐