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

为何在并发基准测试中全局锁性能优于全序锁?

为什么全局锁方案比全序锁方案在高线程数下性能更好?

我在完成操作系统作业时,对比了两种死锁避免的实现方案:全局锁方案(vector-avoid-hold-and-wait.c)和全序锁方案(vector-global-order.c)。原本以为多了一把全局锁的方案会因为额外的锁竞争导致性能更差,但实际测试结果显示,随着线程数增加,全局锁方案的耗时反而明显低于全序锁方案,想搞清楚背后的原因。

两种方案的核心实现

1. 全局锁方案

void vector_add(vector_t *v_dst, vector_t *v_src) {
    // put GLOBAL lock around all lock acquisition...
    Pthread_mutex_lock(&global);
    Pthread_mutex_lock(&v_dst->lock);
    Pthread_mutex_lock(&v_src->lock);
    Pthread_mutex_unlock(&global);
    int i;
    for (i = 0; i < VECTOR_SIZE; i++) {
        v_dst->values[i] = v_dst->values[i] + v_src->values[i];
    }
    Pthread_mutex_unlock(&v_dst->lock);
    Pthread_mutex_unlock(&v_src->lock);
}

2. 全序锁方案

void vector_add(vector_t *v_dst, vector_t *v_src) {
    if (v_dst < v_src) {
        Pthread_mutex_lock(&v_dst->lock);
        Pthread_mutex_lock(&v_src->lock);
    } else if (v_dst > v_src) {
        Pthread_mutex_lock(&v_src->lock);
        Pthread_mutex_lock(&v_dst->lock);
    } else {
        // special case: src and dst are the same
        Pthread_mutex_lock(&v_src->lock);
    }
    int i;
    for (i = 0; i < VECTOR_SIZE; i++) {
        v_dst->values[i] = v_dst->values[i] + v_src->values[i];
    }
    Pthread_mutex_unlock(&v_src->lock);
    if (v_dst != v_src)
        Pthread_mutex_unlock(&v_dst->lock);
}

测试结果

# 全局锁方案耗时
./vector-avoid-hold-and-wait -t -n 16 -l 100000 -d
Time: 0.29 seconds

./vector-avoid-hold-and-wait -t -n 32 -l 100000 -d
Time: 0.36 seconds

./vector-avoid-hold-and-wait -t -n 64 -l 100000 -d
Time: 0.74 seconds

./vector-avoid-hold-and-wait -t -n 99 -l 100000 -d
Time: 1.11 seconds

# 全序锁方案耗时
./vector-global-order -t -n 16 -l 100000 -d
Time: 0.25 seconds

./vector-global-order -t -n 32 -l 100000 -d
Time: 0.54 seconds

./vector-global-order -t -n 64 -l 100000 -d
Time: 1.35 seconds

./vector-global-order -t -n 99 -l 100000 -d
Time: 1.95 seconds

性能差异的核心原因

1. 锁等待模式导致的上下文切换开销不同

全序锁方案看起来是细粒度锁,但实际执行时,线程会先获取第一个vector锁,然后尝试获取第二个。如果第二个锁被其他线程占用,当前线程会持有第一个锁的同时进入阻塞状态。这种情况下,操作系统会触发上下文切换,把CPU让给其他线程,而第一个锁会被一直持有,导致其他需要这个锁的线程也阻塞,形成连锁等待,上下文切换的开销会随着线程数增加快速累积。

而全局锁方案是先获取全局锁,一次性拿到两个vector锁后立刻释放全局锁。线程等待的是全局锁,而不是持有一个锁等待另一个。全局锁的持有时间极短(只有两次Pthread_mutex_lock的时间),所以全局锁的竞争开销很小,但避免了“持有锁等待”的情况,大幅减少了上下文切换的次数。

2. 全局锁的实际开销远低于预期

你之前担心的“多一把锁带来的额外开销”其实被高估了。全局锁只是用来保证锁的获取顺序,它的持有时间非常短,线程拿到全局锁后几乎立刻就能拿到两个vector锁并释放全局锁。在高并发场景下,这种短持有时间的锁竞争带来的开销,远低于全序锁方案中频繁的上下文切换和锁持有等待的开销。

3. 高线程数下的放大效应

当线程数较少时(比如16线程),全序锁的上下文切换次数不多,所以性能和全局锁接近。但随着线程数增加,全序锁中“持有一个锁等待另一个”的冲突概率呈指数级上升,上下文切换的开销被不断放大,而全局锁方案的开销增长则平缓得多,最终在高线程数下反超全序锁。

内容的提问来源于stack exchange,提问作者肯安定

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 05:36:16