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 會自動放進子線程

相關文章
相關標籤/搜索