Links

28.锁|性能分析

前言

是面试中较为常见的内容,在这个越来越卷的行情下,你觉得你对的知识了解的够深(卷)么?

一、 iOS的锁

1.1 经典的性能对比图

下面是一张经典的各种锁方案的性能对比图,相信很多人都见过,出自ibireme大佬。
01
但是这已经是多年以前的测试对比了,现如今又是什么样的结果呢?我们自己来测试一下吧!

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.26898860931396ms
test_dispatch_semaphore_t: 37.284016609191895ms
test_os_unfair_lock_lock: 31.321048736572266ms
test_pthread_mutex_t: 32.119035720825195ms
test_NSlock: 33.952951431274414ms
test_NSCondition: 33.511996269226074ms
test_PTHREAD_MUTEX_RECURSIVE: 32.86397457122803ms
test_NSRecursiveLock: 34.38997268676758ms
test_NSConditionLock: 40.94898700714111ms
test_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.75501251220703ms
test_dispatch_semaphore_t: 39.17098045349121ms
test_os_unfair_lock_lock: 37.19806671142578ms
test_pthread_mutex_t: 35.0489616394043ms
test_NSlock: 37.10508346557617ms
test_NSCondition: 34.54601764678955ms
test_PTHREAD_MUTEX_RECURSIVE: 32.772064208984375ms
test_NSRecursiveLock: 34.829020500183105ms
test_NSConditionLock: 39.30199146270752ms
test_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)。

参考