同步调用并发队列与串行队列行为相似,为何读写问题推荐用并发队列?
并发队列解决线程安全读写问题的优势说明
你给出的示例中并发队列表现和串行队列一致,是提交方式导致的特例,和队列本身的特性无关:你在同一个线程中循环调用queue.sync提交任务,sync会阻塞当前线程等待任务执行完成后才返回,才会提交下一个任务,相当于在提交侧就把所有任务串行化了,不管底层队列是并发还是串行,最终都会表现为串行执行。
业内推荐用并发队列搭配barrier解决存储属性的线程安全读写问题,核心原因是读写场景的需求和两种队列的特性匹配度差异:
- 读写场景的核心规则:读读可并行,读写/写写必须互斥。读多写少是绝大多数业务场景的常态,读操作的并发度直接决定整体性能。
- 串行队列的缺陷:所有任务无论读写都必须依次执行,哪怕同时有多个读请求,也只能逐个调度,完全浪费了多核心CPU的并行能力,读操作越多性能损耗越大。
- 并发队列+barrier的优势:
- 读操作正常提交到并发队列即可,多个读请求可以同时在不同核心执行,性能相比串行队列有数量级的提升。
- 写操作通过barrier标识提交(Swift中写法为
queue.async(flags: .barrier) { 写逻辑 }),barrier会保证写任务执行时,队列中所有之前的任务都已完成,执行期间不会调度其他任何任务,写完成后才会继续调度后续任务,完美满足读写互斥的安全要求。
回到你提到的主队列同步调用读的场景:哪怕你从主队列同步提交读操作,只要有其他线程也同时提交了读请求,这些读任务依然可以在并发队列中并行执行,和串行队列所有任务强制排队的表现依然有本质差异。只有当所有读写任务都从同一个线程依次同步提交这种极端特殊的场景下,两者的表现才会一致,这种场景在实际业务中非常少见。
你给出的示例代码如果将sync改为async,差异会立刻体现:并发队列会同时调度执行10个任务,而串行队列依然会逐个执行。
let queue = DispatchQueue(label: "queue_label", attributes: .concurrent) // concurrent queue for i in 1..<11 { queue.sync { printNumber(from: i*10, to: (i*10) + 9) } }
内容的提问来源于stack exchange,提问作者the monk
相关产品推荐
相关产品推荐

