724 字
4 分钟
锁|性能分析
前言
锁是面试中较为常见的内容,在这个越来越卷的行情下,你觉得你对锁的知识了解的够深(卷)么?
一、 iOS的锁
1.1 经典的性能对比图
下面是一张经典的各种锁方案的性能对比图,相信很多人都见过,出自ibireme大佬。

但是这已经是多年以前的测试对比了,现如今又是什么样的结果呢?我们自己来测试一下吧!
1.2 锁的性能测试
测试代码
用 Swift 的方式来测试一下各个锁 10W 次加锁解锁的耗时吧,顺便熟悉下 Swift 下各种锁的用法:
class ViewController: UIViewController {
override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .brown }
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { test_OSSpinLock() test_dispatch_semaphore_t() test_os_unfair_lock_lock() test_pthread_mutex_t() test_NSlock() test_NSCondition() test_PTHREAD_MUTEX_RECURSIVE() test_NSRecursiveLock() test_NSConditionLock() test_synchronized() }
let excuteTimes = 100_000
func test_OSSpinLock() { var lock = OS_SPINLOCK_INIT let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { OSSpinLockLock(&lock) OSSpinLockUnlock(&lock) } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_OSSpinLock: \(deta)ms") }
func test_dispatch_semaphore_t() { let lock = DispatchSemaphore(value: 1) let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { _ = lock.wait(timeout: .distantFuture) lock.signal() } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_dispatch_semaphore_t: \(deta)ms") }
func test_os_unfair_lock_lock() { var lock = os_unfair_lock.init() let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { os_unfair_lock_lock(&lock) os_unfair_lock_unlock(&lock) } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_os_unfair_lock_lock: \(deta)ms") }
func test_pthread_mutex_t() { var lock = pthread_mutex_t() pthread_mutex_init(&lock, nil) let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { pthread_mutex_lock(&lock) pthread_mutex_unlock(&lock) } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_pthread_mutex_t: \(deta)ms") }
func test_NSlock() { let lock = NSLock() let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { lock.lock() lock.unlock() } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_NSlock: \(deta)ms") }
func test_NSCondition() { let lock = NSCondition() let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { lock.lock() lock.unlock() } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_NSCondition: \(deta)ms") }
func test_PTHREAD_MUTEX_RECURSIVE() { var mutext_recurive = pthread_mutex_t() var attr = pthread_mutexattr_t() pthread_mutexattr_init(&attr) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE) pthread_mutex_init(&mutext_recurive, &attr) let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { pthread_mutex_lock(&mutext_recurive) pthread_mutex_unlock(&mutext_recurive) } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_PTHREAD_MUTEX_RECURSIVE: \(deta)ms") }
func test_NSRecursiveLock() { let lock = NSRecursiveLock() let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { lock.lock() lock.unlock() } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_NSRecursiveLock: \(deta)ms") }
func test_NSConditionLock() { let lock = NSConditionLock() let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { lock.lock() lock.unlock() } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_NSConditionLock: \(deta)ms") }
func test_synchronized() { let start = CFAbsoluteTimeGetCurrent() for _ in 0..<excuteTimes { // Swift 的 @synchronized objc_sync_enter(self) objc_sync_exit(self) } let end = CFAbsoluteTimeGetCurrent() let deta = (end - start) * 1000 print("test_synchronized: \(deta)ms") }}ARM64 架构
iPhoneX 下
test_OSSpinLock: 70.26898860931396mstest_dispatch_semaphore_t: 37.284016609191895mstest_os_unfair_lock_lock: 31.321048736572266mstest_pthread_mutex_t: 32.119035720825195mstest_NSlock: 33.952951431274414mstest_NSCondition: 33.511996269226074mstest_PTHREAD_MUTEX_RECURSIVE: 32.86397457122803mstest_NSRecursiveLock: 34.38997268676758mstest_NSConditionLock: 40.94898700714111mstest_synchronized: 49.324989318847656ms从快到慢:
- os_unfair_lock_lock
- pthread_mutex_t
- PTHREAD_MUTEX_RECURSIVE
- NSCondition
- NSlock
- NSRecursiveLock
- dispatch_semaphore_t
- NSConditionLock
- synchronized
- OSSpinLock
非 ARM64
iPhone8 模拟器下
test_OSSpinLock: 37.75501251220703mstest_dispatch_semaphore_t: 39.17098045349121mstest_os_unfair_lock_lock: 37.19806671142578mstest_pthread_mutex_t: 35.0489616394043mstest_NSlock: 37.10508346557617mstest_NSCondition: 34.54601764678955mstest_PTHREAD_MUTEX_RECURSIVE: 32.772064208984375mstest_NSRecursiveLock: 34.829020500183105mstest_NSConditionLock: 39.30199146270752mstest_synchronized: 39.29495811462402ms从快到慢:
- PTHREAD_MUTEX_RECURSIVE
- NSCondition
- NSRecursiveLock
- pthread_mutex_t
- NSlock
- os_unfair_lock_lock
- OSSpinLock
- dispatch_semaphore_t
- synchronized
- NSConditionLock
总结
此处的结果并不能作为绝对结论。根据设备硬件及运行情况有不同,有兴趣可以自行进行调试。但总体各方案间的差距并没有到非常致命的地步。
synchronized 仍然是开发中我们最常使用的一种,性能OK、使用方便(不用操心 lock unlock)。