基本的 GCD 使用
| 同步异步 \ 队列 | 全局并行队列 | 手动创建的串行队列 | 主队列 | 
| 同步(sync) | 没有开启新线程
 串行执行任务 | 没有开启新线程
 串行执行任务 | 死锁 | 
| 异步(async) | 有开启新线程
 并行执行任务 | 有开启新线程
 串行执行任务 | 没有开启新线程
 串行执行任务 | 
串行队列
创建串行队列
在使用 GCD 的时候先写 dispatch
在 C 语言中,定义对象通常是以_t或者Ref结尾的
特点:依次顺序执行
在非 ARC 中需要释放队列:dispatch_release(q)
DISPATCH_QUEUE_SERIAL 串行 (宏定义了:#define DISPATCH_QUEUE_SERIAL NULL)
DISPATCH_QUEUE_CONCURRENT 并行
| 12
 
 | dispatch_queue_t q = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
 
 | 
创建任务
同步任务
不会开启新的线程
dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);
串行队列中,同步任务在主线程工作,所有任务顺序执行
| 12
 3
 4
 5
 
 | for (int i = 0; i < 10; i++) {dispatch_sync(q, ^{
 NSLog(@"%zd   %@",i , [NSThread currentThread]);
 });
 }
 
 | 
异步任务
只能开一条线程
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
串行队列中,异步任务最多只能开一条线程,所有任务顺序执行
串行队列,异步任务,在多线程中,是斯坦福大学最推荐的一种多线程方式
优点:将任务放在其他线程中工作,每个任务顺序执行
缺点:并发能力不强,最多只能使用一条线程
| 12
 3
 4
 5
 
 | for (int i = 0; i < 10; i++) {dispatch_async(q, ^{
 NSLog(@"%zd   %@",i , [NSThread currentThread]);
 });
 }
 
 | 
并行队列
创建并行队列
dispatch_queue_t q = dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT);
创建任务
同步任务
不会开启新的线程
dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);
在实际开发中,同步任务可以保证执行完成之后,才让后续的异步任务开始执行,用于控制任务之间的先后顺序
| 12
 3
 4
 5
 6
 
 | NSLog(@"================2.1同步任务================");for (int i = 0; i < 10; i++) {
 dispatch_sync(q, ^{
 NSLog(@"%zd   %@",i , [NSThread currentThread]);
 });
 }
 
 | 
异步任务
会在多条线程上工作,具体开多少条线程,由系统决定
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
仍然是按照任务添加到队列中的顺序被调度,知识执行先后可能会有差异
能够将耗时的操作放到子线程中工作
与串行队列相比,开启多条线程(系统决定),并发性能更好,但是执行的先后顺序不固定
| 12
 3
 4
 5
 
 | for (int i = 0; i < 10; i++) {dispatch_async(q, ^{
 NSLog(@"%zd   %@",i , [NSThread currentThread]);
 });
 }
 
 | 
全局并行(并发)队列(使用的更为普遍)
与自定义并行队列的区别就是名字不同,其他完全相同
获取全局队列
与自定义并行队列的区别就是名字不同,其他相同
dispatch_queue_t q = dispatch_get_global_queue(long identifier, unsigned long flags);
关于dispatch_queue_priority_t
| 12
 3
 4
 
 | #define DISPATCH_QUEUE_PRIORITY_HIGH        2#define DISPATCH_QUEUE_PRIORITY_DEFAULT     0
 #define DISPATCH_QUEUE_PRIORITY_LOW         (-2)
 #define DISPATCH_QUEUE_PRIORITY_BACKGROUND  INT16_MIN
 
 | 
| 12
 3
 4
 
 | ```objc
 dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 //等同于dispatch_queue_t q = dispatch_get_global_queue(0, 0);
 
 | 
创建任务
同步任务
| 12
 3
 4
 5
 
 | for (int i = 0; i < 10; i++) {dispatch_sync(q, ^{
 NSLog(@"%zd   %@",i , [NSThread currentThread]);
 });
 }
 
 | 
异步任务
| 12
 3
 4
 5
 
 | for (int i = 0; i < 10; i++) {dispatch_async(q, ^{
 NSLog(@"%zd   %@",i , [NSThread currentThread]);
 });
 }
 
 | 
主队列
专门在主线程上工作的队列,不能开线程
获取主线程
| 1
 | dispatch_queue_t q = dispatch_get_main_queue();
 | 
创建任务
同步任务
注意:不要使用同步任务,会发生死锁
| 12
 3
 4
 5
 
 | for (int i = 0; i < 10; i++) {dispatch_sync(q, ^{
 NSLog(@"%zd   %@",i , [NSThread currentThread]);
 });
 }
 
 | 
异步任务,在主线程上依次顺序执行
| 12
 3
 4
 5
 
 | for (int i = 0; i < 10; i++) {dispatch_async(q, ^{
 NSLog(@"%zd   %@",i , [NSThread currentThread]);
 });
 }
 
 | 
GCD 多线程同步等问题
串行队列中可以将一个任务放到另一个任务完成之后继续,这里讨论并行队列同步问题。
dispatch_barrier_async
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
dispatch_barrier_async必定在前面创建的任务运行完之后才会调用,并且其之后创建的任务必定在其运行完之后才会运行,与 dispatch_barrier_async 代码 位置 执行时间有关。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 
 | dispatch_queue_t concurrentQueue = dispatch_queue_create("tbd.tech", DISPATCH_QUEUE_CONCURRENT);dispatch_async(concurrentQueue, ^(){
 NSLog(@"dispatch-1");
 });
 dispatch_async(concurrentQueue, ^(){
 NSLog(@"dispatch-2");
 });
 dispatch_async(concurrentQueue, ^(){
 NSLog(@"dispatch-3");
 });
 dispatch_async(concurrentQueue, ^(){
 NSLog(@"dispatch-4");
 });
 dispatch_async(concurrentQueue, ^(){
 NSLog(@"dispatch-5");
 });
 
 
 dispatch_barrier_async(concurrentQueue, ^(){
 NSLog(@"dispatch-barrier");
 });
 
 dispatch_async(concurrentQueue, ^(){
 NSLog(@"dispatch-a");
 });
 dispatch_async(concurrentQueue, ^(){
 NSLog(@"dispatch-b");
 });
 
 | 
dispatch_group_async & dispatch_group_notify
| 12
 3
 4
 5
 6
 7
 
 | dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,
 dispatch_block_t block);
 
 dispatch_group_notify(dispatch_group_t group,
 dispatch_queue_t queue,
 dispatch_block_t block);
 
 | 
dispatch_group_async是创建 GCD 的 group 操作。在dispatchGroup中所有任务运行完之后,才会调用dispatch_group_notify,与代码的顺序无关。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 
 | dispatch_queue_t dispatchQueue = dispatch_queue_create("tbd.tech", DISPATCH_QUEUE_CONCURRENT);dispatch_group_t dispatchGroup = dispatch_group_create();
 
 dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
 NSLog(@"dispatch-1 : %@", [NSThread currentThread]);
 });
 dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
 NSLog(@"dispatch-2 : %@", [NSThread currentThread]);
 });
 
 
 dispatch_group_notify(dispatchGroup, dispatch_get_main_queue(), ^(){
 NSLog(@"Success : %@", [NSThread currentThread]);
 });
 
 dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
 NSLog(@"dispatch-3 : %@", [NSThread currentThread]);
 });
 dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
 NSLog(@"dispatch-4 : %@", [NSThread currentThread]);
 });
 dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
 NSLog(@"dispatch-5 : %@", [NSThread currentThread]);
 });
 dispatch_group_async(dispatchGroup, dispatchQueue, ^(){
 NSLog(@"dispatch-6 : %@", [NSThread currentThread]);
 });
 
 | 
dispatch_apply
| 12
 
 | dispatch_apply(size_t iterations, dispatch_queue_t queue,DISPATCH_NOESCAPE void (^block)(size_t));
 
 | 
dispathc_apply 是 dispatch_sync 和dispatch_group的关联 API.它以指定的次数将指定的 Block 加入到指定的队列中。并等待队列中操作全部完成.
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | NSArray *array = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10",@"11",@"12",@"13",@"14",@"15",@"16",@"17",@"18",@"19",@"20"];
 dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
 dispatch_async(queue, ^{
 dispatch_apply(array.count, queue,  ^(size_t index){
 
 NSLog(@"%@", array[index]);
 });
 
 dispatch_async(dispatch_get_main_queue(), ^{
 NSLog(@"处理完成,回到主线程。");
 });
 });
 
 | 
dispatch_semaphore & @synchronized
要防止对同一数据产生写冲突,就需要设置加锁(@synchronized)或者采用信号量(dispatch_semaphore)的方式。
dispatch_semaphore
| 12
 3
 4
 5
 6
 
 | dispatch_semaphore_t dispatch_semaphore_create(long value);
 
 long dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout);
 
 long dispatch_semaphore_signal(dispatch_semaphore_t dsema);
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | NSMutableArray *array = [NSMutableArray array];dispatch_group_t group = dispatch_group_create();
 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
 NSDate *date = [[NSDate alloc] init];
 for (int index = 0; index < 100000; ++index) {
 dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
 [array addObject:[NSNumber numberWithInt:index]];
 dispatch_semaphore_signal(semaphore);
 });
 }
 dispatch_group_notify(group, dispatch_get_main_queue(), ^{
 NSLog(@"%lu", (unsigned long)array.count);
 double time = [date timeIntervalSinceNow];
 NSLog(@"time %f", time);
 });
 
 | 
@synchronized
试验了一下性能不如dispatch_semaphore
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | NSMutableArray *array = [NSMutableArray array];dispatch_group_t group = dispatch_group_create();
 NSDate *date = [[NSDate alloc] init];
 for (int index = 0; index < 100000; ++index) {
 dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
 @synchronized(array) {
 [array addObject:[NSNumber numberWithInt:index]];
 }
 });
 }
 dispatch_group_notify(group, dispatch_get_main_queue(), ^{
 NSLog(@"%lu", (unsigned long)array.count);
 double time = [date timeIntervalSinceNow];
 NSLog(@"time %f", time);
 });
 
 |