*串行与并行

串行队列与并发队列都是基于队列,所以遵循先进先出的原则。串行执行时,各个任务按顺序执行,完成一个后才能进行下一个;并发执行各个任务也是按顺序开始执行,但是无需等待前一个完成才能执行。

单个线程的并行队列采用并发方式,而多核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时就会一直等待(阻塞所在线程),否则就可以正常执行。