You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何我的MCS锁性能表现逊于简易自旋锁?

一篇技术文章指出:

自旋锁除了单纯自旋等待锁的问题外,还存在一个根本性缺陷:每次尝试获取锁都需要将包含该锁的缓存行迁移到本地CPU。对于竞争激烈的锁,这种缓存行抖动会严重影响性能。
...
通过将自旋锁扩展为每个CPU的独立结构,MCS锁能够消除简易自旋锁遇到的大部分缓存行抖动问题,尤其是在锁竞争激烈的场景下。

为验证这一效果,我编写了基准测试代码,完整代码可查看指定仓库版本。

简易自旋锁实现

代码基于一篇互斥锁、自旋锁性能测试的文章修改而来。该锁在基准测试结果中标记为spinlock (amd)。

pub struct RawSpinlock {
    locked: AtomicBool,
}

unsafe impl RawMutex for RawSpinlock {
    // ...

    fn lock(&self) {
        loop {
            let was_locked = self.locked.load(Ordering::Relaxed);
            if !was_locked
                && self
                    .locked
                    .compare_exchange_weak(was_locked, true, Ordering::Acquire, Ordering::Relaxed)
                    .is_ok()
            {
                break;
            }
            spin_loop()
        }
    }

    unsafe fn unlock(&self) {
        self.locked.store(false, Ordering::Release);
    }
}

MCS锁实现

代码基于NUMA自旋锁项目修改,该项目源自libc-alpha邮件列表的讨论。该锁在基准测试结果中标记为spinlock (mcs)。

struct Node {
    next: AtomicPtr<Self>,
    locked: AtomicBool,
}

#[thread_local]
static mut NODE: Node = Node {
    next: AtomicPtr::new(null_mut()),
    locked: AtomicBool::new(false),
};

pub struct RawSpinlock {
    tail: AtomicPtr<Node>,
}

unsafe impl RawMutex for RawSpinlock {
    // ...

    fn lock(&self) {
        unsafe {
            NODE.next = AtomicPtr::new(null_mut());
            NODE.locked = AtomicBool::new(false);
        }

        let node = unsafe { &mut NODE as *mut _ };
        let prev = self.tail.swap(node, Ordering::Acquire);

        if prev.is_null() {
            return;
        }

        unsafe { (*prev).next.store(node, Ordering::Relaxed) };
        while unsafe { !NODE.locked.load(Ordering::Acquire) } {
            spin_loop();
        }
    }

    unsafe fn unlock(&self) {
        let node = &mut NODE as *mut _;
        let mut next = NODE.next.load(Ordering::Relaxed);

        if next.is_null() {
            if self
                .tail
                .compare_exchange(node, null_mut(), Ordering::Release, Ordering::Relaxed)
                .is_ok()
            {
                return;
            }
            loop {
                next = NODE.next.load(Ordering::Relaxed);
                if !next.is_null() {
                    break;
                }
                spin_loop();
            }
        }

        unsafe { (*next).locked.store(true, Ordering::Release) };
    }
}

基准测试结果

我的CPU为Ryzen 3700X。测试中启动16个线程,全部竞争2个锁,结果如下:

> cargo run --release -- 16 2 10000 100
Options {
    n_threads: 16,
    n_locks: 2,
    n_ops: 10000,
    n_rounds: 100,
}

spinlock (amd)       avg 6.242695ms   min 4.784792ms   max 10.356368ms
spinlock (mcs)       avg 19.968031ms  min 13.980298ms  max 60.338753ms

可见MCS锁性能明显差于简易自旋锁。即使调整参数为16线程+32锁以模拟低竞争场景,仍未观察到MCS锁的性能优势。

请问是我的实现存在问题,还是MCS锁本身性能不佳?


内容的提问来源于stack exchange,提问作者QuarticCat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 21:18:11