GCD / NSOperation

 GCD 与 NSOperation 的区别 ?xcode

1. GCD 是基于 C 语言写的核心服务, 很是简单高效, 而 NSOperation 是基于 GCD 的一种封装,抽象出来的对象, 因此通常状况下对于任务的依赖和并发数没有要求的状况下, GCD 的效率更高, 开销更小多线程

2. 依赖关系,NSOperation能够设置两个NSOperation之间的依赖,第二个任务依赖于第一个任务完成执行,GCD没法设置依赖关系,不过能够经过dispatch_barrier_async来实现这种效果并发

3. KVO(键值对观察),NSOperation和容易判断Operation当前的状态(是否执行,是否取消),对此GCD没法经过KVO进行判断异步

4. 优先级,NSOperation能够设置自身的优先级,可是优先级高的不必定先执行,GCD只能设置队列的优先级,没法在执行的block设置优先级;async

5. 继承,NSOperation是一个抽象类实际开发中经常使用的两个类是NSInvocationOperation和NSBlockOperation,一样咱们能够自定义NSOperation,GCD执行任务能够自由组装,没有继承那么高的代码复用度;函数

总的来讲: 若是对于任务的并发数和任务之间的依赖关系没有要求, 能够直接使用 GCD, 不然使用 NSOperation 能够知足对任务的控制ui

GCDspa

GCD 面对的不是线程, GCD 面对的只有队列和任务这两个概念, 你不用管在哪一个线程, 只须要把任务按正确的同步/异步的方式添加进串行/并发队列便可线程

  • 串行队列(先进入队列的任务先出队列,每次只执行一个任务) 顺序执行 
  • 并发队列(依然是“先入先出”,不过能够造成多个任务并发)   异步添加能够并发执行 同步添加只能顺序执行
  • 主队列(这是一个特殊的串行队列,并且队列中的任务必定会在主线程中执行)
  1. 同步执行  都不会开启新的线程
  2. 异步执行  会开启新的线程 除了主队列

          同步                          异步code

主队列    死锁              不会开启新线程(顺序执行)

串行队列   在当前线程执行(顺序执行)     开启一个新的线程(顺序执行)      

并发队列   在当前线程执行(顺序执行)     开启一个或多个线程(并发执行)

下面是例子

//异步 + 并行队列
- ( 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---" );
 
// 结果 start 123 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---" );
}
 
// 结果: start 123 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---" );
}
 
// 结果 start 123 end  不会开启新的线程 会异步执行   主队列就运行在主线程
 
// 同步 + 主队列  死锁
 
*************************** GCD 实现全部异步操做完成以后执行的任务 *****************************
//先建立一个组
dispatch_group_t group = dispatch_group_create();
// 异步添加到任务到并行队列
 
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  //请求1 NSLog(@"Request_1");
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//请求2 NSLog(@"Request_2");
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//请求3 NSLog(@"Request_3");
});
// 当全部任务都执行完成以后 才执行
 
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
//界面刷新 NSLog(@"任务均完成,刷新界面");
});
//  打印结果 2 1 3 刷新界面   会开启多线程 异步任务完成的顺序不受控制

*******************************若是须要添加任务之间的依赖**************************
  1. dispatch_group_t group =dispatch_group_create();  
  2.         dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{  
  3.                           NSLog(@"任务1");  
  4.          });  
  5.       
  6.         dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{  
  7.                          NSLog(@"任务2");  
  8.          });  
  9.       
  10.         dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{  
  11.                     NSLog(@"任务3");  
  12.     }); 
//  任务 1 2 并行执行 执行完以后执行 3 
 
  1. dispatch_queue_t myqueue =dispatch_queue_create("myqueue.queue",DISPATCH_QUEUE_CONCURRENT);  
  2.      dispatch_async(myqueue, ^{  
  3.         NSLog(@"任务1");  
  4.     });  
  5.       
  6.     dispatch_async(myqueue, ^{  
  7.         NSLog(@"任务2");  
  8.     });  
  9.       
  10.     dispatch_barrier_async(myqueue, ^{  
  11.         NSLog(@"任务3");  
  12.     });  
  13.       
  14.     dispatch_async(myqueue, ^{  
  15.         NSLog(@"任务4");  
  16.     });  
  17.     dispatch_async(myqueue, ^{  
  18.         NSLog(@"任务5");  
  19.     });  
//  1 2 并行执行 执行完以后执行3 最后执行 4 5 
// *dispatch_barrier_async 会等待当前队列的任务执行完以后再执行dispatch_barrier_async(myqueue, ^{
       NSLog(@"任务3");

     });

// NSOperation
NSOperation 实现多线程的使用步骤分为三步:
  1. 建立操做:先将须要执行的操做封装到一个 NSOperation 对象中。
  2. 建立队列:建立 NSOperationQueue 对象。
  3. 将操做加入到队列中:将 NSOperation 对象添加到 NSOperationQueue 对象中。

以后呢,系统就会自动将 NSOperationQueue 中的 NSOperation 取出来,在新线程中执行操做

使用NSOperation子类的方式有三种: 
NSInvocationOperation 
NSBlockOperation 
自定义子类继承NSOperation,实现响应的方法

先看看NSInvocationOperation的使用:

1. 同步执行的 直接操做 不加入 queue

NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"这是一个参数"];
[operation start]; }
/// 将参数与当前线程打印
- (void)demo:(NSString *)str { NSLog(@"%@--%@",str,[NSThread currentThread]); }

2. 加入队列 异步执行
// 建立操做队列
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
// 建立操做(最后的object参数是传递给selector方法的参数)
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"这是一个参数"];
// 将操做添加到操做队列
[operationQueue addOperation:operation]; }
/// 将参数与当前线程打印
- (void)demo:(NSString *)str { NSLog(@"%@--%@",str,[NSThread currentThread]); }
开启了一个子线程  且是异步执行的
只有将operation放到一个NSOperationQueue中,才会异步执行操做。

再看看NSBlockOperation

NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^(){ NSLog(@"%@",[NSThread currentThread]); }];
// 开始执行任务 [operation start];
// 直接執行 同步執行 不會開啟新線程//建立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];


// 為 operation 添加依賴關係 
  1.  NSOperationQueue *queue=[[NSOperationQueue alloc] init];  
  2.     //建立操做  
  3.     NSBlockOperation *operation1=[NSBlockOperation blockOperationWithBlock:^(){  
  4.         NSLog(@"执行第1次操做,线程:%@",[NSThread currentThread]);  
  5.     }];  
  6.     NSBlockOperation *operation2=[NSBlockOperation blockOperationWithBlock:^(){  
  7.         NSLog(@"执行第2次操做,线程:%@",[NSThread currentThread]);  
  8.     }];  
  9.     NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^(){  
  10.         NSLog(@"执行第3次操做,线程:%@",[NSThread currentThread]);  
  11.     }];  
  12.     //添加依赖  
  13.     [operation1 addDependency:operation2];  
  14.     [operation2 addDependency:operation3];  
  15.     //将操做添加到队列中去  
  16.     [queue addOperation:operation1];  
  17.     [queue addOperation:operation2];  
  18.     [queue addOperation:operation3]; 
先執行3 然後 2 最後1  都是在同一個子線程執行的
// 设置最大并发数

  // 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]);  // 打印当前线程
 
   
         }
 
   
     }];
当最大并发操做数为1时,操做是按顺序串行执行的,而且一个操做完成以后,下一个操做才开始执行。当最大操做并发数为2时,操做是并发执行的,能够同时执行两个操做。而开启线程数量是由系统决定的,不须要咱们来管理
 

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 会自动放进子线程

相关文章
相关标签/搜索