GCD / NSOperation
GCD 与 NSOperation 的区别 ?
1. GCD 是基于 C 语言写的核心服务, 非常简单高效, 而 NSOperation 是基于 GCD 的一种封装,抽象出来的对象, 所以一般情况下对于任务的依赖和并发数没有要求的情况下, GCD 的效率更高, 开销更小
2. 依赖关系,NSOperation可以设置两个NSOperation之间的依赖,第二个任务依赖于第一个任务完成执行,GCD无法设置依赖关系,不过可以通过dispatch_barrier_async来实现这种效果
3. KVO(键值对观察),NSOperation和容易判断Operation当前的状态(是否执行,是否取消),对此GCD无法通过KVO进行判断
4. 优先级,NSOperation可以设置自身的优先级,但是优先级高的不一定先执行,GCD只能设置队列的优先级,无法在执行的block设置优先级;
5. 继承,NSOperation是一个抽象类实际开发中常用的两个类是NSInvocationOperation和NSBlockOperation,同样我们可以自定义NSOperation,GCD执行任务可以自由组装,没有继承那么高的代码复用度;
总的来说: 如果对于任务的并发数和任务之间的依赖关系没有要求, 可以直接使用 GCD, 否则使用 NSOperation 可以满足对任务的控制
GCD
GCD 面对的不是线程, GCD 面对的只有队列和任务这两个概念, 你不用管在哪个线程, 只需要把任务按正确的同步/异步的方式添加进串行/并发队列即可
三种队列:
- 串行队列(先进入队列的任务先出队列,每次只执行一个任务) 顺序执行
- 并发队列(依然是“先入先出”,不过可以形成多个任务并发) 异步添加可以并发执行 同步添加只能顺序执行
- 主队列(这是一个特殊的串行队列,而且队列中的任务一定会在主线程中执行)
两种执行方式:
- 同步执行 都不会开启新的线程
- 异步执行 会开启新的线程 除了主队列
同步 异步
主队列 死锁 不会开启新线程(顺序执行)
串行队列 在当前线程执行(顺序执行) 开启一个新的线程(顺序执行)
并发队列 在当前线程执行(顺序执行) 开启一个或多个线程(并发执行)
下面是例子
//异步 + 并行队列- (void)asyncConcurrent{ //创建一个并行队列 dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT); NSLog(@"---start---"); //使用异步函数封装三个任务 dispatch_async(queue, ^{ NSLog(@"任务1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"任务2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"任务3---%@", [NSThread currentThread]); }); NSLog(@"---end---");}结果: start end 3 2 1 // 开启3个新的线程 同时执行的 没有先后
//异步 + 串行队列- (void)asyncSerial{ //创建一个串行队列 dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL); NSLog(@"---start---"); //使用异步函数封装三个任务 dispatch_async(queue, ^{ NSLog(@"任务1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"任务2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"任务3---%@", [NSThread currentThread]); }); NSLog(@"---end---");}// 结果 start end 123 开启一个新的线程 顺序执行
//同步 + 并行队列- (void)syncConcurrent{ //创建一个并行队列 dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_CONCURRENT); NSLog(@"---start---"); //使用同步函数封装三个任务 dispatch_sync(queue, ^{ NSLog(@"任务1---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"任务2---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"任务3---%@", [NSThread currentThread]); }); NSLog(@"---end---");- (void)syncSerial{ //创建一个串行队列 dispatch_queue_t queue = dispatch_queue_create("标识符", DISPATCH_QUEUE_SERIAL); NSLog(@"---start---"); //使用异步函数封装三个任务 dispatch_sync(queue, ^{ NSLog(@"任务1---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"任务2---%@", [NSThread currentThread]); }); dispatch_sync(queue, ^{ NSLog(@"任务3---%@", [NSThread currentThread]); }); NSLog(@"---end---");}- (void)asyncMain{ //获取主队列 dispatch_queue_t queue = dispatch_get_main_queue(); NSLog(@"---start---"); //使用异步函数封装三个任务 dispatch_async(queue, ^{ NSLog(@"任务1---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"任务2---%@", [NSThread currentThread]); }); dispatch_async(queue, ^{ NSLog(@"任务3---%@", [NSThread currentThread]); }); NSLog(@"---end---");}- dispatch_group_t group =dispatch_group_create();
- dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
- NSLog(@"任务1");
- });
- dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
- NSLog(@"任务2");
- });
- dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
- NSLog(@"任务3");
- });
- dispatch_queue_t myqueue =dispatch_queue_create("myqueue.queue",DISPATCH_QUEUE_CONCURRENT);
- dispatch_async(myqueue, ^{
- NSLog(@"任务1");
- });
- dispatch_async(myqueue, ^{
- NSLog(@"任务2");
- });
- dispatch_barrier_async(myqueue, ^{
- NSLog(@"任务3");
- });
- dispatch_async(myqueue, ^{
- NSLog(@"任务4");
- });
- dispatch_async(myqueue, ^{
- NSLog(@"任务5");
- });
});
- 创建操作:先将需要执行的操作封装到一个 NSOperation 对象中。
- 创建队列:创建 NSOperationQueue 对象。
- 将操作加入到队列中:将 NSOperation 对象添加到 NSOperationQueue 对象中。
之后呢,系统就会自动将 NSOperationQueue 中的 NSOperation 取出来,在新线程中执行操作
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation,实现响应的方法
先看看NSInvocationOperation的使用:
1. 同步执行的 直接操作 不加入 queue
2. 加入队列 异步执行
再看看NSBlockOperation:
22 NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
23 NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
24 }];
25
26 //添加操作 在子线程异步执行
27 [operation addExecutionBlock:^{
28 NSLog(@"NSBlockOperation1------%@",[NSThread currentThread]);
29 }];
30
// 在子线程 异步执行
31 [operation addExecutionBlock:^{
32 NSLog(@"NSBlockOperation2------%@",[NSThread currentThread]);
33 }];
34
35 //开启执行操作
36 [operation start];
- NSOperationQueue *queue=[[NSOperationQueue alloc] init];
- //创建操作
- NSBlockOperation *operation1=[NSBlockOperation blockOperationWithBlock:^(){
- NSLog(@"执行第1次操作,线程:%@",[NSThread currentThread]);
- }];
- NSBlockOperation *operation2=[NSBlockOperation blockOperationWithBlock:^(){
- NSLog(@"执行第2次操作,线程:%@",[NSThread currentThread]);
- }];
- NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^(){
- NSLog(@"执行第3次操作,线程:%@",[NSThread currentThread]);
- }];
- //添加依赖
- [operation1 addDependency:operation2];
- [operation2 addDependency:operation3];
- //将操作添加到队列中去
- [queue addOperation:operation1];
- [queue addOperation:operation2];
- [queue addOperation:operation3];
// 设置最大并发数
// 1.创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2.设置最大并发操作数 queue.maxConcurrentOperationCount = 1; // 串行队列// queue.maxConcurrentOperationCount = 2; // 并发队列// queue.maxConcurrentOperationCount = 8; // 并发队列 // 3.添加操作 [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i++) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"1---%@", [NSThread currentThread]); // 打印当前线程 } }]; [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i++) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程 } }]; [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i++) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"3---%@", [NSThread currentThread]); // 打印当前线程 } }]; [queue addOperationWithBlock:^{ for (int i = 0; i < 2; i++) { [NSThread sleepForTimeInterval:2]; // 模拟耗时操作 NSLog(@"4---%@", [NSThread currentThread]); // 打印当前线程 } }];
NSBlockOperation最开始的任务是在主线程中执行的,再给NSBlockOperation添加的额外的任务是在子线程中执行的,程序自动帮助开启了子线程。
GCD队列和NSOperationQueue队列类型比较:
GCD的队列类型:
(1)并发队列:a.全局 b.自己创建的
(2)串行队列:a.主队列 b.自己创建的
NSOperationQueue队列类型:
(1)主队列[NSOperationQueue mainQueue],添加到主队列中的任务,都会在主线程中执行。
(2)其他队列(串行、并发),添加到其他队列中的任务,都会自动放在子线程中执行。
NSOperation默认是同步执行的。
创建一个 operation 直接 start 执行的话会在 main thread , 再添加额外的block 任务的时候会开启新的线程异步执行
创建一个 operation 和 queue 并把 operation 放进 queue 会自动放进子线程

浙公网安备 33010602011771号