16. 并发基础
并发的目标是“并行处理 + 主线程保持流畅”。核心是:任务拆分、线程安全、正确回主线程。
一、GCD 基础
1. 主队列与全局队列
DispatchQueue.main.async {
// 更新 UI
}
DispatchQueue.global(qos: .userInitiated).async {
// 高优先级任务
}
2. 延迟执行
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
print("delay")
}
二、DispatchGroup:并行任务汇总
let group = DispatchGroup()
for i in 0..<3 {
group.enter()
DispatchQueue.global().async {
print("task \(i)")
group.leave()
}
}
group.notify(queue: .main) {
print("all done")
}
三、Barrier:读写隔离
let queue = DispatchQueue(label: "cache.queue", attributes: .concurrent)
var cache: [String: String] = [:]
func read(_ key: String) -> String? {
queue.sync { cache[key] }
}
func write(_ key: String, _ value: String) {
queue.async(flags: .barrier) {
cache[key] = value
}
}
四、OperationQueue:依赖与取消
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2
let op1 = BlockOperation { print("download") }
let op2 = BlockOperation { print("decode") }
let op3 = BlockOperation { print("render") }
op2.addDependency(op1)
op3.addDependency(op2)
queue.addOperations([op1, op2, op3], waitUntilFinished: false)
五、线程安全与锁
1. NSLock
final class SafeCounter {
private var value = 0
private let lock = NSLock()
func increase() {
lock.lock()
value += 1
lock.unlock()
}
func get() -> Int {
lock.lock()
let v = value
lock.unlock()
return v
}
}
2. 串行队列
final class SerialCache {
private let queue = DispatchQueue(label: "serial.cache")
private var map: [String: String] = [:]
func set(_ key: String, _ value: String) {
queue.async { self.map[key] = value }
}
func get(_ key: String, completion: @escaping (String?) -> Void) {
queue.async { completion(self.map[key]) }
}
}
六、Semaphore:限制并发数量
let semaphore = DispatchSemaphore(value: 2)
for i in 0..<5 {
DispatchQueue.global().async {
semaphore.wait()
print("task \(i)")
Thread.sleep(forTimeInterval: 1)
semaphore.signal()
}
}
七、Swift Concurrency(async/await)
func fetchData() async throws -> String {
try await Task.sleep(nanoseconds: 200_000_000)
return "data"
}
Task {
let value = try await fetchData()
print(value)
}
TaskGroup 并行
func loadAll() async -> [String] {
await withTaskGroup(of: String.self) { group in
for i in 0..<3 {
group.addTask { "item-\(i)" }
}
var result: [String] = []
for await item in group { result.append(item) }
return result
}
}
八、常见错误
- 回调中直接更新 UI(必须回主线程)
- 数据结构并发读写导致崩溃
- 把 IO 放在主线程
- 过度并发导致资源争抢
并发的关键是“少而稳”,限制并发数、避免共享可变状态,才能保证性能和稳定性。