GCD to Explain In Detail
任务和队列
任务:
- block中代码;
- 执行任务两种方式:同步执行(sync)和 异步执行(async);
- 同步异步区别:
- 是否等待队列的任务执行结束
- 是否具备开启新线程的能力
队列:
一种特殊的线性表,遵循先进先出(FIFO)原则
两种队列:串行队列 和 并发队列
串行并发区别:
- 执行顺序不同
- 开启线程数不同
系统提供的串行队列:主队列 (Main Dispatch Queue)
所有放到主队列中的任务,都会放在主线程执行
dispatch_get_main_queue();系统提供的并发队列:全局并发队列 (Global DisPatch Queue)
dispatch_get_global_queue(优先级,0);
优先级:high、default、low、background;
总结
区别 | 并发队列 | 串行队列 | 主队列 |
---|---|---|---|
同步(sync) | 没有开启新线程串行执行任务 | 没有开启新线程串行执行任务 | 主线程调用:死锁卡住不执行;其他线程调用:没有开启新线程,串行执行任务 |
异步(async) | 有开启新线程并发执行任务 | 有开启新线程(1条)串行执行任务 | 没有开启新线程,串行执行任务 |
GCD线程间通信
// 获取全局并发队列 |
GCD其他方法
1.GCD栅栏方法:dispatch_barrier_async
在执行完栅栏前面的操作之后,才执行栅栏操作,最后再执行栅栏后边的操作。
2.GCD 延时执行方法:dispatch_after
我们经常会遇到这样的需求:在指定时间(例如3秒)之后执行某个任务。可以用 GCD 的
dispatch_after
函数来实现。需要注意的是:
dispatch_after
函数并不是在指定时间之后才开始执行处理,而是在指定时间之后将任务追加到主队列中。严格来说,这个时间并不是绝对准确的,但想要大致延迟执行任务,dispatch_after函数是很有效的。
/** |
3.GCD 一次性代码(只执行一次):dispatch_once
我们在创建单例、或者有整个程序运行过程中只执行一次的代码时,我们就用到了 GCD 的
dispatch_once
函数。使用dispatch_once
函数能保证某段代码在程序运行过程中只被执行1次,并且即使在多线程的环境下,dispatch_once
也可以保证线程安全。
- (void)once { |
4.GCD 快速迭代方法:dispatch_apply
- 通常我们会用 for 循环遍历,但是 GCD 给我们提供了快速迭代的函数
dispatch_apply
。 dispatch_apply
按照指定的次数将指定的任务追加到指定的队列中,并等待全部队列执行结束。
如果是在串行队列中使用
dispatch_apply
,那么就和 for 循环一样,按顺序同步执行。可这样就体现不出快速迭代的意义了。我们可以利用并发队列进行异步执行。比如说遍历 0~5 这6个数字,for 循环的做法是每次取出一个元素,逐个遍历。
dispatch_apply
可以 在多个线程中同时(异步)遍历多个数字。还有一点,无论是在串行队列,还是异步队列中,
dispatch_apply
都会等待全部任务执行完毕,这点就像是同步操作,也像是队列组中的dispatch_group_wait
方法。
5.GCD 队列组:dispatch_group
有时候我们会有这样的需求:分别异步执行2个耗时任务,然后当2个耗时任务都执行完毕后再回到主线程执行任务。这时候我们可以用到 GCD 的队列组。
调用队列组的
dispatch_group_async
先把任务放到队列中,然后将队列放入队列组中。或者使用队列组的dispatch_group_enter
、dispatch_group_leave
组合 来实现dispatch_group_async
。调用队列组的
dispatch_group_notify
回到指定线程执行任务。或者使用dispatch_group_wait
回到当前线程继续向下执行(会阻塞当前线程)。
5.1 dispatch_group_notify
- 监听 group 中任务的完成状态,当所有的任务都执行完成后,追加任务到 group 中,并执行任务。
- (void)groupNotify { |
5.2 dispatch_group_wait
- 暂停当前线程(阻塞当前线程),等待指定的 group 中的任务执行完成后,才会往下继续执行。
- (void)groupWait { |
5.3 dispatch_group_enter、dispatch_group_leave
dispatch_group_enter
标志着一个任务追加到 group,执行一次,相当于 group 中未执行完毕任务数+1dispatch_group_leave
标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数-1。- 当 group 中未执行完毕任务数为0的时候,才会使
dispatch_group_wait
解除阻塞,以及执行追加到dispatch_group_notify
中的任务。
dispatch_group_t group = dispatch_group_create(); |
6. GCD 信号量:dispatch_semaphore
GCD 中的信号量是指 Dispatch Semaphore,是持有计数的信号。类似于过高速路收费站的栏杆。可以通过时,打开栏杆,不可以通过时,关闭栏杆。在 Dispatch Semaphore 中,使用计数来完成这个功能,计数为0时等待,不可通过。计数为1或大于1时,计数减1且不等待,可通过。
Dispatch Semaphore 提供了三个函数。
- dispatch_semaphore_create:创建一个Semaphore并初始化信号的总量
- dispatch_semaphore_signal:发送一个信号,让信号总量加1
- dispatch_semaphore_wait:可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。
注意:信号量的使用前提是:想清楚你需要处理哪个线程等待(阻塞),又要哪个线程继续执行,然后使用信号量。
Dispatch Semaphore 在实际开发中主要用于:
- 保持线程同步,将异步执行任务转换为同步执行任务
- 保证线程安全,为线程加锁