Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。
使用GCD,不需要管理线程,线程管理完全托管给GCD。
用纯c写的,一般用block来描述
首先要了解同步和异步,串行和并行的区别:
同步:a请求b任务,只有b任务给予a反馈,a才能继续执行
异步:a请求b任务时,a无需等待b回应就可以继续执行其他操作
串行:一个任务完成下一个任务菜可能开始
并行:在同一时刻,两个任务开始执行,但互不干扰
1.dispatch queue
dispatch queue分成以下三种:
1)运行在主线程的Main queue,通过dispatch_get_main_queue获取。
2)并行队列global dispatch queue(可以多个线程并行,任务可以同时执行),通过dispatch_get_global_queue获取,由系统创建三个不同优先级的dispatch queue。并行队列的执行顺序与其加入队列的顺序相同。
3)串行队列serial queues(所有线程串行,或者只有一个线程,任务依次执行 )一般用于按顺序同步访问,可创建任意数量的串行队列,各个串行队列之间是并发的。
当想要任务按照某一个特定的顺序执行时,串行队列是很有用的。串行队列在同一个时间只执行一个任务。我们可以使用串行队列代替锁去保护共享的数据。和锁不同,一个串行队列可以保证任务在一个可预知的顺序下执行。
serial queues通过dispatch_queue_create创建,可以使用函数dispatch_retain和dispatch_release去增加或者减少引用计数。
//创建串行的队列 //第一个参数表示queue的名字,,,第二个参数表示queue的类型 |
//创建并行的队列 dispatch_queue_t queue_2 = dispatch_queue_create("queue.2", DISPATCH_QUEUE_CONCURRENT); |
//获取全局并发的queue(属于并行队列) //第一个参数表示优先级,,,第二个参数暂时没用 dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); |
//获取管理主线程的queue(属于串行队列) //提交给main queue的任务可能不会立马被执行,而是在主线程的Run Loop检测到有dispatch 提交过来的任务时才会执行 dispatch_queue_t main_queue = dispatch_get_main_queue(); |
2.提交任务
分为两种:同步提交和异步提交
两个参数:
。第一个参数表示提交到的queue
。第二个参数表示任务详情,这里用block的方式描述一个任务,原因很简单,Block也是 纯C实现的,而平时使用的Invocation或者target+selector方式都是面向对象的。
//获取全局并发的queue dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //1.同步提交 //如果使用同步请求方式,会造成卡死当前线程的后果。
|
//2.异步提交 //异步提交任务后,dispatch_async()函数直接返回,无需等待block执行结束。 NSLog(@"OK.....");
|
//3.同步提交多次任务 dispatch_queue_t queue_1 = dispatch_queue_create("queue.1", DISPATCH_QUEUE_SERIAL); dispatch_queue_t queue_2 = dispatch_queue_create("queue.2", DISPATCH_QUEUE_CONCURRENT); //比较同步提交多个任务和遍历数组哪个快 (在不关心数组顺序的前提下) //遍历数组 NSLog(@"start forin"); //数组遍历 for (NSString* a in array) { NSLog(@"fisined forin"); NSLog(@"start apply"); //同步提交多个任务 dispatch_apply(array.count, queue_2, ^(size_t i) { NSLog(@"fisined apply"); |
3.死锁
同步提交在某种情况下会造成死锁,即卡死。
//主线程(属于串行队列)死锁 //不会打印出任何东西 dispatch_queue_t main_queue = dispatch_get_main_queue(); //同步执行 dispatch_sync(main_queue, ^{ NSLog(@"OK"); 程序默认是从上往下执行的,但是程序走到dispatch_sync时,又会先走block再返回到dispatch_sync,这样就会照成冲突,形成死锁 |
//串行队列 dispatch_queue_t queue_1 = dispatch_queue_create("queue.1", DISPATCH_QUEUE_SERIAL); //异步提交 dispatch_async(queue_1, ^{ //不会被打印 //同步提交 dispatch_sync(queue_1, ^{ NSLog(@"bbb"); }); NSLog(@"ccccc"); }); NSLog(@"aaaa"); |
死锁解决方案:串行队列异步执行,并行队列同步执行。 串行队列中 ,同步提交任务给本身队列,就会出现死锁。要想不出现死锁就把串行队列改为并行队列,或把同步提交任务改为异步提交。
|
4. Dispatch Group
什么是dispatch group,就像我们在NSOperation中添加依赖一样,如果我们一个任务需要等待其他一些任务完成才能执行时
4.1 提交任务
分为两步:
1.创建group
2.提交任务,并且把任务添加到group中
//1.创建group dispatch_group_t group = dispatch_group_create(); dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) |
//2.提交一个任务给global_queue ,并且添加到group中 / / global_queue并非是一个queue,但group必须是同一个 / / group只有异步提交,没有同步提交 dispatch_group_async(group, global_queue, ^{ }); |
//3.异步提交终极任务给queue ,main_queue //终极任务就相当于operation1依赖于Operation2一样,只是operation1不能和之前提交任务一样,而是需要终极任务dispatch_group_notify提交 //异步提交 不阻塞当前线程 //要想阻塞当前线程,一直等待group所有任务结束,需要用到dispatch_group_wait dispatch_group_notify(group, dispatch_get_main_queue(), ^{ |
//创建dispatch time //可以自定义超时时间,只等待一定的时间 dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(200 * NSEC_PER_SEC)); //4.自定义超时时间 //设置超时时间,阻塞当前线程 dispatch_group_wait(group, time); //买饮料的时间过长,已经超过了等待的时间,所以很难再执行 NSLog(@"...."); NSLog(@"看电视"); |