// 方式一:NSLock class Counter { privatelet lock = NSLock() privatevarcount = 0 func increment() { lock.lock() defer { lock.unlock() } count += 1 } } // 堆代码 duidaima.com // 方式二:串行队列 class Counter { privatelet queue = DispatchQueue(label: "counter.queue") privatevarcount = 0 func increment() { queue.sync { count += 1 } } }说实话,这两种方式都不算优雅。NSLock 容易忘记解锁(虽然有 defer 帮忙),而 GCD 的队列又显得有些重。
actor Counter { private var count = 0 func increment() { count += 1 } }这个知识点之前也有专门讲过,错过的小伙伴可以回去补一下。
import Synchronization final class Counter { privatelet mutex = Mutex(0) func increment() { mutex.withLock { value in value += 1 } } func get() -> Int { mutex.withLock { $0 } } }看到了吗?不需要 async/await,API 简洁优雅,而且性能还特别好!
// 测试代码 func testPerformance() async { letcount = 10_000_000 let start = Date() // 创建并发任务 await withTaskGroup(of: Void.self) { group in for_in0..<count { group.addTask { // 执行累加操作 } } } let elapsed = Date().timeIntervalSince(start) print("耗时:\(elapsed) 秒") }测试结果让我大吃一惊:
同步机制 | 耗时(秒) | 相对性能 |
---|---|---|
Mutex | 3.65 | 100% (基准) |
OSAllocatedUnfairLock | 4.42 | 83% |
Actor | 7.51 | 49% |
NSLock | 8.31 | 44% |
DispatchQueue | 9.28 | 39% |
final class ThreadSafeCache { privatelet cache = Mutex([String: Data]()) func set(_ key: String, value: Data) { cache.withLock { dict in dict[key] = value } } func get(_ key: String) -> Data? { cache.withLock { dict in dict[key] } } func removeAll() { cache.withLock { dict in dict.removeAll() } } }2. 避免死锁
// ❌ 错误示例:会导致死锁 mutex.withLock { value in // 一些操作... mutex.withLock { _in// 💥 死锁! // ... } } // ✅ 正确做法:提取公共逻辑 privatefunc doSomething(_ value: inout Int) { // 共享的逻辑 } func method1() { mutex.withLock { value in doSomething(&value) } } func method2() { mutex.withLock { value in doSomething(&value) } }3. 配合泛型使用
// 创建一个线程安全的泛型容器 finalclass ThreadSafeBox<T> { privatelet mutex: Mutex<T> init(_ value: T) { self.mutex = Mutex(value) } func update(_ transform: (inout T) -> Void) { mutex.withLock { value in transform(&value) } } func get() -> T { mutex.withLock { $0 } } } // 使用示例 let box = ThreadSafeBox([1, 2, 3]) box.update { array in array.append(4) }Mutex vs Actor:如何选择?
与现有同步代码集成
import Synchronization let counter = Atomic(0) // 原子累加 counter.add(1, ordering: .relaxed) // 原子读取 let value = counter.load(ordering: .relaxed) // 比较并交换 counter.compareExchange( expected: 0, desired: 1, ordering: .relaxed )Atomic 的性能比 Mutex 还要好,但只能用于基本类型的简单操作。如果你只需要对数字进行原子操作,Atomic 是最佳选择。
兼容老代码:继续用 NSLock 或 GCD