精选文章

16. 并发基础

2020-03-09 · 并发

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
    }
}

八、常见错误

  1. 回调中直接更新 UI(必须回主线程)
  2. 数据结构并发读写导致崩溃
  3. 把 IO 放在主线程
  4. 过度并发导致资源争抢

并发的关键是“少而稳”,限制并发数、避免共享可变状态,才能保证性能和稳定性。

JJ

作者简介

专注于内容创作、产品策略与设计实践。欢迎交流合作。

上一篇 下一篇