正在加载今日诗词....
3 min read

GCD 探究

多线程业务处理是一种提高效率,优化体验的通用做法, iOS 中常常使用的其中之一就是 GCD , 其中一个比较有意思的 dispatch_barrier 最容易让人迷惑...

dispatch_barrier

应用场景: 并发队列中,存在顺序问题, 某个任务执行完成后才能执行其余操作.

易错点: dispatch_barrier_asyndispatch_barrier_sync 的区别

这里首先要明白两个概念:

  • 同步与异步的区别
    • 同步: 阻塞 当前线程, 必须要将任务代码执行完成后,才能返回.
      • 同步一定不会开子线程
    • 异步: 不阻塞 当前线程, 提交任务后, 直接返回, 任务何时执行,不关心
  • 队列 : 数据结构的一种, 遵循先进先出 FIFO 的原则
    • 队列是 管理任务 , 而不是线程!!!
    • 并发队列: 队列中的元素为 一个一个的任务, 任务执行需要耗时, 并发的概念是 任务是按照添加的顺序来从队列中拿出来, 给对应的线程来执行, 关键点是, 并发的队列不会等待任务执行完成就可以取出下一个任务元素.
      • 开始执行 是有顺序,结束执行没有顺序. 当然这个开始执行并不是说执行代码,仅仅是说将任务从队列中拿出来, 给相应的线程, 可能后出来的任务创建线程快,也说不定.
  • 串行队列与并发队列的特性.
    - 异步不一定会开启子线程, 串行队列,任务仍然是当前线程来处理, 并发队列则会开启子线程
  • 容易混淆: 任务提交队列的顺序 与 任务从队列中出列,并执行的顺序

dispatch_barrier_asyn

  • dispatch_barrier_asyn 只能配合 dispatch_queue_create 创建的并发队列,才能起到阻塞当前添加任务的作用, 否则就相当于一个简单的 dispatch_async
  • dispatch_barrier_asyn 配合自建的 并发队列,任务执行特点是 dispatch_barrier_asyn 之前的任务无序执行,都完成后, 再执行 dispatch_barrier_asyn提交的任务, 然后无序执行之后的添加任务.

dispatch_barrier_sync

考虑问题, 一定要明白前提条件!!!

  • dispatch_barrier_sync 首先要明白, 它有 dispatch_sync 的特性, 也就是阻塞当前线程,它会等待当前任务执行完成!!!!, 不论当前的线程是哪种,无关队列
  • 如果是 dispatch_barrier_sync 提交到的队列一个串行队列或者是一个全局并发队列,效果等同 dispatch_sync; 如果是串行队列, 那就可能死锁 GG 了,注意一定是有可能,因为创建任务的队列和dispatch_barrier_sync提交到的队列如果是不同的队列就没问题. 而创建dispatch_barrier_sync任务的队列和dispatch_barrier_sync任务提交到的队列是同一个队列则会死锁. 比如当前主线程创建的任务,提交到主队列
  • 如果是 dispatch_barrier_sync 提交到自定义并发队列, 也就是在并发队列屁股后面添加了一个任务,那么等到并发队列出列到 dispatch_barrier_sync提交的任务后, 该任务不会执行, 而是会等待已经出列的任务,全部执行完成后,才会执行, 并且阻塞当前线程.

总结: 自定义的并发队列, 使用 dispatch_barrier_syncdispatch_barrier_asyn 区别只是在 对当前线程的影响中, 对于并发队列中的任务执行顺序是没有影响的,但是因为 dispatch_barrier_sync 会阻塞当前线程, 所以在 dispatch_barrier_sync 执行任务的时候, 后续的任务是没有提交到队列的, 而dispatch_barrier_asyn 在执行任务的时候, 因为不阻塞当前线程, 所以其他任务可以正常提交, 只是不能在 dispatch_barrier_asyn 的任务执行完之前执行而已!!!

参考