GCD简介(Grand Central Dispatch)
GCD是从ios4开始引入的新一代多线程编程技术
GCD需要用到一个系统库lib dispatch,lib dispatch是苹果的一个开发库,我们在使用时不需要导入这个库 因为系统层也在用这个库 所以这个库不导入它也会被加载进来
使用GCD开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并有计划的执行任务,ios的内核会基于DIspatch Queue中的任务数量、CPU核数和CPU负荷等当前的系统状态来决定创建多少个线程和并发执行多少个任务
一、Dispatch Queue(调度队列)
使用GCD进行编程,开发者要做的只是定义想要执行的任务并追加到适当的Dispatch Queue中。调度队列中的任务按照FIFO(先入先出)的顺序进行处理,也就是先进入的任务现行处理
二、调度队列分为串行和并发两种
串行VS并发
串行:要求等待正在执行的任务完成,再执行下一个,也就是说只会创建一个线程来执行任务
并发:队列中后面的任务可以不必等待正在执行的任务完成就可以执行,也就是同时可以执行多个任务,也就是说会创建多个线程同时执行多个任务
1、串行队列
创建一个队列会开辟一个分线程,添加到串行队列中的任务在新线程中会按照添加的顺兴执行。串行队列经常处理一些需要顺序访问的任务。创建多个串行队列,多个串行队列间是并行的。
创建串行队列代码如下
/**
* @author沈超, 16-07-15 14:07:33
*
*创建串行队列,添加到此队列的任务回一个挨着一个执行此队列会开辟一条线程执行任务
*
* @param "com.cmcc.serialQueue"唯一标识符,一般域名反写+队列名,用于调试,崩溃报告中查看
* @param NULL指定创建queue的类型,NULL或DISPATCH_QUEUE_SERIAL表示串行队列
*
* @return <#return value description#>
*/
dispatch_queue_tserial_Queue=dispatch_queue_create("com.cmcc.serialQueue",NULL);/**
* @author沈超, 16-07-15 14:07:10
*
*创建并发队列,添加到此队列的任务会并发执行,此队列会创建多个线程执行任务
*
* @param "com.cmcc.concurrent_queue"唯一标识符,一般域名反写+队列名,用于调试,崩溃报告中查看
* @param DISPATCH_QUEUE_CONCURRENT指定创建queue的类型,DISPATCH_QUEUE_SERIAL表示并发队列
*
* @return <#return value description#>
*/
dispatch_queue_tconcurrent_queue=dispatch_queue_create("com.cmcc.concurrent_queue",DISPATCH_QUEUE_CONCURRENT);
三、系统提供队列全局队列和主队列
①全局队列
全局队列是一个在全局都可以获取的并发队列,而是只需要获取全局队列使用即可。全局队列有四种,即4个优先级,分别是high、default、low、background
获取全局队列的代码如下
dispatch_queue_t dispatch_global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
②主队列
主队列是一个在全局都可以获取的串行调度队列,该队列中的任务都是在主线程中执行的。因为是在主线程中执行,所以一般会将用户界面更新等一些必须在主线程中执行的任务追加带主队列中。
获取主队列代码如下
dispatch_queue_tmain_queue =dispatch_get_main_queue();
队列类型
创建的串行队列
创建的并发队列
获取的全局队列
获取的主队列
四、dispatch_async 和 dispatch_sync
任务:定义想要执行的任务 使用block语法来完成
同步提交:dispatch_sync同步添加任务到队列中,它是等待任务完成之后再继续执行。
异步提交:dispatch_async异步添加任务到异步队列中,它不会做任何等待
注意:同步提交不管提交到哪个什么队列,不会开辟新线程,在当前线程中执行
特别注意:同步提交要慎重使用,尤其是在当前队列中同步提交任务到当前队列,会造成线程死锁
五、dispatch_group
如果想在dispatch_queue中所有的任务执行完成后再做某种操作,在串行队列中,可以把该操作放到最后一个任务执行完成后执行,但是在并行队列中怎么做呢,这就有了dispatch_group成组操作
创建一个group
使用dispatch_group_async向组中添加队列和任务
当并行队列中的任务执行完时,使用dispatch_group_notify执行block通知group中的任务执行完毕
六、dispatch_semaphore
dispatch_semaphore信号量记忆计数器的一种多线程同步机制,在多线个线程访问共有资源时候,会因为多线程的特性而引发数据出错的问题。
GCD中有3个信号量有关的操作:
dispatch_semaphore_create 信号量创建
dispatch_semaphore_wait 信号量等待 wait会阻塞线程并且检测信号量的值,直到信号量值大于0才会往下执行,
同时对信号量执行-1操作
dispatch_semaphore_signal 发送通知+1 如果信号量值小于0直接唤醒线程继续执行
场景1:并发队列中的两个操作 操作1完成后操作2才能开始(线程间通信)
场景2:控制并发队列中并发任务数量
七、dispatch_once
使用Dispatch_once函数实现单例中的线程同步
该函数参数1 dispatch_once用于检查代码块是否已经被调度的谓词(其实就是长整形,实际上作为BOOL使用) 加static使用静态变量 以保证只执行一次。
参数2 希望在程序的生命周期内仅调用一次的代码块(适用于单例)如果被多个线程同时调用,该函数会同步等待,直至代码块完成
优势:
1、线程安全
2、仅需要少量代码块实现单例
八、dispatch_barrier_async
在并发队列中,使用dispatch_barrier_async添加的任务,队列在执行此任务时,队列中的其他任务不会执行,执行完成后该队列回复原有执行状态,继续并发执行
当一系列的操作都需要依赖于某个操作时,使用dispatch_barrier_async
注意:使用用户创建的并发队列(在系统队列中阻塞无效,等价于dispatch_async)
九、Dispatch_apply
Dispatch_apply是Dispatch_sync和dispatch_group的关联API。
dispatch_apply函数值将指定次数的指定任务(block)添加到queue中(此处queue一般为并发队列)
dispatch_apply是同步函数,会阻塞当前线程直到所有循环中任务执行完成,这些任务在queue中的执行顺序是不确定的(要并发,要提高效率)
十、Dispatch_after&&dispatch_time
Tips:
并发VS并行
并发指的是同时执行了多个任务,在多个任务间切换,一般是指同一时间间隔同时执行了多个任务(一般指单核)
并行值的是同时执行多个任务,一般是指同一时刻同时执行了多少任务(一般指多核)
并行:(多核)
cpu1:任务part1
thread:_________________
cpu2:任务part2
thread:_________________
并发:(单核)
thread1— — — — — — — —任务part1
thread2 — — — — — — — —任务part2
并行要求并发,并发并不能保证并行(单核)