GCD复习

GCD的优势

  • GCD 可用于多核的并行运算
  • GCD 会自动利用更多的 CPU 内核(比如双核、四核)
  • GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)
  • 程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码

** GCD 任务和队列**

任务:在线程中执行操作代码,在 GCD 中是放在 block 中的。
执行任务有两种方式:
同步执行(sync)和异步执行(async)。

同步执行(sync)
同步添加任务到指定的队列中,在添加的任务执行结束之前,会一直等待,直到队列里面的任务完成之后再继续执行。
只能在当前线程中执行任务,不具备开启新线程的能力。

异步执行(async)
异步添加任务到指定的队列中,它不会做任何等待,可以继续执行任务。
可以在新的线程中执行任务,具备开启新线程的能力。

队列(Dispatch Queue)
队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)

串行队列(Serial Dispatch Queue)
每次只有一个任务被执行。让任务一个接着一个地执行。(只开启一个线程,一个任务执行完毕后,再执行下一个任务)

并发队列(Concurrent Dispatch Queue)
可以让多个任务并发(同时)执行。(可以开启多个线程,并且同时执行任务)

并发队列的并发功能只有在异步(dispatch_async)函数下才有效

GCD 的使用步骤

  • 创建一个队列(串行队列或并发队列)
  • 将任务追加到任务的等待队列中,系统会根据任务类型执行任务(同步执行或异步执行)

特别注意

  • 在主线程中调用同步执行 + 主队列 = 死锁
  • 在子线程中调用同步执行 + 主队列 = 串行执行

GCD 线程间的通信

在其他线程中先执行任务,执行完了之后回到主线程执行主线程的相应操作

GCD 的其他方法

  • GCD 栅栏方法:dispatch_barrier_async
    函数会等待前边追加到并发队列中的任务全部执行完毕之后,再将指定的任务追加到该异步队列中

  • GCD 延时执行方法:dispatch_after
    在指定时间之后将任务追加到主队列中。但时间并不精确

  • GCD 一次性代码(只执行一次):dispatch_once
    在创建单例、或者有整个程序运行过程中只执行一次的代码时,就用到了 GCD 的这个函数,能保证某段代码在程序运行过程中只被执行1次,并且即使在多线程的环境下,也可以保证线程安全。

  • GCD 快速迭代方法:dispatch_apply
    按照指定的次数将指定的任务追加到指定的队列中,并等待全部队列执行结束。

  • 串行队列中使用 dispatch_apply,就和for循环一样,按顺序同步执行。

  • 异步并行队列使用,在多个线程中同时执行,顺序不可控。

  • GCD 队列组:dispatch_group
    分别异步执行2个耗时任务,然后当2个耗时任务都执行完毕后再回到主线程执行任务。这时候我们可以用到 GCD 的队列组。

  • 调用队列组的 dispatch_group_async 先把任务放到队列中,然后将队列放入队列组中。或者使用队列组的 dispatch_group_enter、dispatch_group_leave组合 来实现dispatch_group_async。

  • 调用队列组的 dispatch_group_notify 回到指定线程执行任务。或者使用 dispatch_group_wait 回到当前线程继续向下执行(会阻塞当前线程)。

dispatch_group_notify
监听 group 中任务的完成状态,当所有的任务都执行完成后,才执行dispatch_group_notify block中追加的任务。

dispatch_group_wait
暂停当前线程(阻塞当前线程),等待指定的 group 中的任务执行完成后,才会往下继续执行。
使用dispatch_group_wait 会阻塞当前线程。

dispatch_group_enter、dispatch_group_leave
dispatch_group_enter 标志着一个任务追加到 group,执行一次,相当于 group 中未执行完毕任务数+1

dispatch_group_leave 标志着一个任务离开了 group,执行一次,相当于 group 中未执行完毕任务数-1。

当 group 中未执行完毕任务数为0的时候,才会使dispatch_group_wait解除阻塞,以及执行追加到dispatch_group_notify中的任务。

dispatch_group_enter、dispatch_group_leave组合,其实等同于dispatch_group_async。

GCD 信号量:dispatch_semaphore
GCD中的信号量是指 Dispatch Semaphore,是持有计数的信号。
计数为0时等待,不可通过。
计数为1或大于1时,计数减1且不等待,可通过。

Dispatch Semaphore 提供了三个函数。

  • dispatch_semaphore_create:创建一个Semaphore并初始化信号的总量
  • dispatch_semaphore_signal:发送一个信号,让信号总量加1
  • dispatch_semaphore_wait:可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。

注意:信号量的使用前提是:想清楚你需要处理哪个线程等待(阻塞),又要哪个线程继续执行,然后使用信号量。

Dispatch Semaphore 线程同步

  • 保持线程同步,将异步执行任务转换为同步执行任务
  • 保证线程安全,为线程加锁
    异步执行耗时任务,并使用异步执行的结果进行一些额外的操作。== 将异步执行任务转换为同步执行任务。
    AFURLSessionManager.m 里面的 tasksForKeyPath: 方法。通过引入信号量的方式,等待异步执行任务结果,获取到 tasks,然后再返回该 tasks。

线程安全(使用 semaphore 加锁)
semaphore 数为1线程安全加锁

dispatch_semaphore_create 创建一个信号量,传入数字为信号总量。到0位锁
dispatch_semaphore_signal 信号量+1 相当于解锁
dispatch_semaphore_wait 信号量-1 相当于加锁

你可能感兴趣的:(GCD复习)