1. 程式人生 > >IOS多執行緒的三種方案

IOS多執行緒的三種方案

IOS多執行緒主要有三種

NSTheard
GCD
NSOperation & NSOperationQueue

NSTheard

這是最輕量級的多執行緒的方法,使用起來最直觀的多執行緒程式設計方法。但是因為需要自己管理執行緒的生命週期,執行緒同步。經常使用NSThread進行除錯,在實際專案中不推薦使用。

//取消執行緒
- (void)cancel;

//啟動執行緒
- (void)start;

//判斷某個執行緒的狀態的屬性
@property (readonly, getter=isExecuting) BOOL executing;
@property
(readonly, getter=isFinished) BOOL finished; @property (readonly, getter=isCancelled) BOOL cancelled; //設定和獲取執行緒名字 -(void)setName:(NSString *)n; -(NSString *)name; //獲取當前執行緒資訊 + (NSThread *)currentThread; //獲取主執行緒資訊 + (NSThread *)mainThread; //使當前執行緒暫停一段時間,或者暫停到某個時刻 + (void)sleepForTimeInterval:(NSTimeInterval
)time; + (void)sleepUntilDate:(NSDate *)date;
//獲取當前執行緒
NSThread *current = [NSThread currentThread];
//獲取主執行緒
NSThread *main = [NSThread mainThread];
NSLog(@"當前執行緒 --- %@",current);
NSLog(@"主執行緒 --- %@",main);

GCD

GCD是基於C語言底層API實現的一套多執行緒併發機制。簡單來說CGD就是把 操作(任務) 放在 佇列 中去執行。你只需定義好操作和佇列就可以了。它是蘋果為多核的並行運算提出的解決方案,所以會自動合理地利用更多的CPU核心(比如雙核、四核),最重要的是它會自動管理執行緒的生命週期(建立執行緒、排程任務、銷燬執行緒),完全不需要我們管理,我們只需要告訴幹什麼就行。

操作分為同步和非同步
同步操作:只會按順序執行,執行順序是確定的。
非同步操作:在序列佇列中執行順序確定,在並行佇列中執行順序不確定
同步(sync) 和 非同步(async) 的主要區別在於會不會阻塞當前執行緒,直到 Block 中的任務執行完畢!
如果是 同步(sync) 操作,它會阻塞當前執行緒並等待 Block 中的任務執行完畢,然後當前執行緒才會繼續往下執行。
如果是 非同步(async)操作,當前執行緒會直接往下執行,它不會阻塞當前執行緒

佇列:用於存放任務。一共有兩種佇列, 序列佇列 和 並行佇列。

這裡寫圖片描述

//獲取主佇列,這是一個特殊的 序列佇列。它用於重新整理 UI,任何需要重新整理 UI 的工作都要在主佇列執行
dispatch_queue_t queue = ispatch_get_main_queue();
//建立序列佇列
dispatch_queue_t q = dispatch_queue_create("my_serial_queue", DISPATCH_QUEUE_SERIAL);
//建立並行佇列
dispatch_queue_t q = dispatch_queue_create("my_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);

使用block來定義操作要執行的程式碼,q是已經定義好的,操作要加入的佇列

//定義同步操作
dispatch_sync(q, ^{
 //要執行的程式碼 
});
//定義非同步操作
dispatch_async(q, ^{
 //要執行的程式碼  
});

1.同步操作不管加入到何種佇列,只會在主執行緒按順序執行

dispatch_queue_t q_serial = dispatch_queue_create("my_serial_queue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t q_concurrent = dispatch_queue_create("my_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 5; ++i) {
 dispatch_sync(q_serial, ^{
 NSLog(@"序列佇列裡的同步任務 %@ %d", [NSThread currentThread], i);
 });
}
for (int i = 0; i < 5; ++i) {
 dispatch_sync(q_concurrent, ^{
 NSLog(@"並行佇列裡的同步任務 %@ %d", [NSThread currentThread], i);
 });
}

2.非同步操作只在非主執行緒的執行緒執行,在序列佇列中非同步操作會在新建的執行緒中按順序執行。

dispatch_queue_t q_serial = dispatch_queue_create("my_serial_queue", DISPATCH_QUEUE_SERIAL);
for(int i = 0; i < 5; ++i){
 dispatch_async(q_serial, ^{
  NSLog(@"序列佇列 -- 非同步任務 %@ %d", [NSThread currentThread], i);
 });
}

3.非同步操作,並行佇列
理論上並行佇列會給每一個非同步操作新建執行緒,然後讓所有的任務併發執行。但是實際上系統能建立的執行緒數量是有限的,當建立的執行緒達到最大執行緒數以後,後面的非同步操作就需要等待前面的操作執行完畢才能得到執行。哪個執行緒操作執行完畢,就把等待的非同步任務安排到哪個執行緒

dispatch_queue_t q_concurrent = dispatch_queue_create("my_concurrent_queue", DISPATCH_QUEUE_CONCURRENT);
for(int i = 0; i < 5; ++i){
 dispatch_async(q_concurrent, ^{
  NSLog(@"並行佇列 -- 非同步任務 %@ %d", [NSThread currentThread], i);
 });
}

NSOperation&NSOperationQueue

蘋果公司把GCD中的操作抽象成NSOperation物件,把佇列抽象成NSOperationQueue物件。
NSOperation 只是一個抽象類,所以不能封裝任務。但它有 2 個子類用於封裝任務。分別是:NSInvocationOperation 和 NSBlockOperation 。

//1.建立NSInvocationOperation物件
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];

//2.開始執行
[operation start];

//3.建立NSBlockOperation物件
  NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
      NSLog(@"%@", [NSThread currentThread]);
  }];

//4.開始任務
[operation start];

NSBlockOperation 還有一個方法:addExecutionBlock: ,通過這個方法可以給 Operation 新增多個執行 Block。這樣 Operation 中的任務 會併發執行,它會 在主執行緒和其它的多個執行緒 執行這些任務.

//1.建立NSBlockOperation物件
      NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
          NSLog(@"%@", [NSThread currentThread]);
      }];

      //新增多個Block
      for (NSInteger i = 0; i < 5; i++) {
          [operation addExecutionBlock:^{
              NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
          }];
      }

 //2.開始任務
 [operation start];

NOTE:addExecutionBlock 方法必須在 start() 方法之前執行,否則就會報錯
設定依賴關係(執行順序)
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@"op1"];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationAction:) object:@"op2"];
//op2在op1之後執行
[op2 addDependency:op1];//這裡需要注意,一定要在addOperation之前設定依賴關係 
[queue addOperation:op1];
[queue addOperation:op2];

在NSOperation & NSOperationQueue中,我們不需要再像GCD那樣定義操作的型別和佇列的型別和控制操作的執行順序了,你只需要直接設定操作的執行順序就可以了。

Pthreads

僅供瞭解

POSIX執行緒(POSIX threads),簡稱Pthreads,是執行緒的POSIX標準。該標準定義了建立和操縱執行緒的一整套API。在類Unix作業系統(Unix、Linux、Mac OS X等)中,都使用Pthreads作為作業系統的執行緒。