> For the complete documentation index, see [llms.txt](https://ryukiedev.gitbook.io/wiki/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ryukiedev.gitbook.io/wiki/ios/di-ceng/28.-suo-xing-neng-fen-xi.md).

# 28.锁｜性能分析

## 前言

`锁`是面试中较为常见的内容，在这个越来越卷的行情下，你觉得你对`锁`的知识了解的够深（卷）么？

## 一、 iOS的锁

### 1.1 经典的性能对比图

下面是一张经典的各种锁方案的性能对比图，相信很多人都见过，出自[ibireme](https://blog.ibireme.com/2016/01/16/spinlock_is_unsafe_in_ios/)大佬。

![01](/files/-MjTz1gYYbrvhhnxLGdA)

但是这已经是多年以前的测试对比了，现如今又是什么样的结果呢？我们自己来测试一下吧！

### 1.2 锁的性能测试

#### 测试代码

用 `Swift` 的方式来测试一下各个锁 `10W` 次加锁解锁的耗时吧，顺便熟悉下 `Swift` 下各种锁的用法：

```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`）。

## 参考

* [不再安全的 OSSpinLock](https://blog.ibireme.com/2016/01/16/spinlock_is_unsafe_in_ios/)
