# 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/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ryukiedev.gitbook.io/wiki/ios/di-ceng/28.-suo-xing-neng-fen-xi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
