闽公网安备 35020302035485号
// 方式一: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