apache / brpc

brpc is an Industrial-grade RPC framework using C++ Language, which is often used in high performance system such as Search, Storage, Machine learning, Advertisement, Recommendation etc. "brpc" means "better RPC".
https://brpc.apache.org
Apache License 2.0
16.56k stars 3.98k forks source link

Active Spinning and queue old bthread at the head for bthread mutex #2749

Closed chenBright closed 2 months ago

chenBright commented 2 months ago

What problem does this PR solve?

Issue Number:

Problem Summary:

golang mutex的演进中有两点优化:

  1. fast path没抢到锁的竞争者,进入slow path之后,立即再抢一次锁,不成功就阻塞在butex中,等下次唤醒在抢锁。进入slow path之后的第一次抢锁大概率是会失败的。[1]
  2. 被唤醒的队头竞争者跟新竞争者抢锁,大概率也是会失败。因为新竞争者占用着cpu且数量很多。如果将队头的竞争者放到队尾,显然不公平,甚至可能出现饥饿问题。[2]

What is changed and the side effects?

Changed:

  1. 进入slow path之后,如果worker线程本地调度队列为空,尝试自旋4次再抢锁,这对于临界区小的场景是有意义的。
  2. 被唤醒的队头竞争者抢锁失败后,会被重新放回队头。

Side effects:


Check List:

wwbmmm commented 2 months ago

有测试这个性能提升的效果吗?

chenBright commented 2 months ago

有测试这个性能提升的效果吗?

  1. 自旋没啥效果,应该是因为触发条件比较苛刻,不好模拟。如果本地调度队列已经空了,进程负载应该不高,不自旋、多一次唤醒,问题也不大。不过mutex进入slow path之前自旋一小会,是经过业界验证过的优化手段,应该在条件满足的情况下,会有一点提升吧。
  2. 测试第二点优化,性能没变化。性能最好的应该是修改之前的,公平性一般会牺牲一些性能。性能和公平性是需要权衡的,golang为了公平性还引入了饥饿模式,让等待队列中饥饿(排队时间超过1ms)的协程直接获得锁,新来的协程直接入队。目前第二点优化了一个公平性的小问题,且不会降低性能,应该是可以接受的。
wwbmmm commented 2 months ago

LGTM