*串行与并行
串行队列与并发队列都是基于队列,所以遵循先进先出的原则。串行执行时,各个任务按顺序执行,完成一个后才能进行下一个;并发执行各个任务也是按顺序开始执行,但是无需等待前一个完成才能执行。
单个线程的并行队列采用并发方式,而多核CPU可同时开启多线程并行执行任务。
*同步和异步
同步不能开启新的线程,异步可以开启新的线程;所以并发队列的并发功能只有在异步下才有效。
同步:在发出一个功能调用时,在没有得到返回结果前,程序不会往下执行。
异步:在发出一个功能调用后即刻返回,程序继续往下执行。
*GCD的使用
一,创建队列
可以使用dispatch_queue_create来创建队列,需要传两个参数;第一个参数表示队列唯一标识,一般采用如应用程序ID一样的逆序全称域名来标识,第二个参数用来识别是串行队列还是并发以列,DISPATCH_QUEUE_SERIAL表示串行以列,DISPATCH_QUEUE_CONCURRENT 表示并发队列。
eg:
dispatch_queue_t queue1 = dispatch_queue_create("com.test.mySerialQueue",DISPATCH_QUEUE_SERIAL)
dispatch_queue_t queue2 = dispatch_queue_create("com.test.myConncurrentQueue",DISPATCH_QUEUE_CONCURRENT)
GCD提供两种默认的队列:
1,特殊的串行队列:主列队,放在主队列中的任务都会放到主线程中去执行,队列获取方式:
dispatch_queue_t mainQueue = dispatch_get_main_queue()
2,全局并发队列:需要传递两个参数,第一个表示优先级,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT,第二个暂时没用,传0即可。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
二,任务执行方法
1,同步执行任务
dispatch_sync(queue, ^{
//执行任务
});
2,异步执行任务
dispatch_async(queue,^{
//do something
});
同步/异步+并发/串行队列执行情况:
方式 | 并发队列 | 串行队列 | 主队列 |
同步执行 | 没有开启新线程 | 执行任务时没有开启新线程 | *主线程调用:会出线死锁 *其它线程调用不会开新线程,串行执行 |
异步执行 | 有开启新线程,并发执行任务有开启新线程 | 主线程串行执行任务 |
三,栅栏操作
在我们需要异步执行两组操作,并且当前一组操作需要等待之前操作执行完后才开始,这就需要一个栅栏操作。
dispatch_barrier_ async异步栅栏、dispatch_barrier_ sync同步栅栏
*在执行栅栏之前的异步操作完成之后,才开始执行栅栏函数,最后再执行栅栏函数后的异步任务。
*多个栅栏函数串行执行
*在使用栅栏函数时,使用自定义并发队列才有意义。如果用的是串行队列或者系统提供的全局并发队列,这个栅栏函数的作用等同于一个同步函数的作用。
四,延迟执行方法:dispatch_after
eg:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)2.0*NSEC_PER_SEC),dispatch_get_main_queue(),^{
});
*dispatch_after并不是在指定时间后开始执行处理,而是在指定时间之后将任务追加到某个队列中,所以时间只是个大概
五,GCD单例执行:dispatch_once
六,快速迭代方法:dispatch_apply当传入并发队列时会利用多核开启多线程执行以提高效率,会等待全部任务执行完毕再执行下步操作
dispatch_queue_tdispatch_queue_create("myCq", DISPATCH_QUEUE_CONCURRENT);
dispatch_apply(6, cQ, ^(size_t iteration) {
});
七,GCD队列组:dispatch_group
1,调用队列组的dispatch_group_async(先把任务放入队列中,再将队列放入组中)
2,或使用dispatch_group_enter、dispatch_group_leave来实现跟dispatch_group_async相同的效果
3,调用dispatch_group_notify回到指定的队列中执行指定的任务,或是使用dispatch_group_wait回到当前线程中继续向下执行操作
4,dispatch_group_notify和dispatch_group_wait的区别在于前者不会阻塞当前线程,而后者会阻塞线程直到指定的时间前group中的任务完成才进行后继操作
eg1:
dispatch_queue_t("myCq", DISPATCH_QUEUE_SERIAL);
dispatch_group_t();
(cG, cQ, ^{
//something
});
(cG, cQ, ^{
//something
});
// dispatch_group_notify(cG, dispatch_get_main_queue(), ^{
// something
// });
dispatch_group_wait(cG, DISPATCH_TIME_FOREVER);
eg2:
dispatch_queue_tdispatch_queue_create("myCq", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t();
(cG);
(cQ,^{
(cG);
});
dispatch_group_enter(cG);
dispatch_async(cQ,^{
(cG);
});
// dispatch_group_notify(cG, dispatch_get_main_queue(), ^{
// });
dispatch_group_wait(cG, DISPATCH_TIME_FOREVER);
八,GCD信号量,可用于保证线程安全,为线程加锁或保持线程同步
信号量是一个整型值,在创建的时候会有一个初始值。当执行dispatch_semaphore_signal
发送信号的时候信号量会加1,dispatch_semaphore_wait
在信号量小于或等于0的时候会一直等待,直到超时,并且会阻塞该线程,当信号量大于0时会继续执行并对信号量执行减1操作。
Dispatch Semaphore提供了三个函数。
dispatch_semaphore_create: 创建一个Semaphore并初始化信号的总量
dispatch_semaphore_signal: 发送一个信号, 让信号总量加1
dispatch_semaphore_wait: 可以使总信号量减1,当信号总量为0时就会一直等待(阻塞所在线程),否则就可以正常执行。