多線程技術之NSThread、Cocoa NSOperation、GCD

最近一直都沒用,也有點忘了,打算好好總結下.

(一)NSThread

(二)Cocoa NSOperation

(三)GCD(全稱:Grand Central Dispatch)

抽象程度層次由低到高,抽象度越高的使用越簡單.

一.詳細介紹:

1.NSThread

優點:比其他兩個輕量級

缺點:需要自己管理線程的生命周期,線程同步.線程同步對數據的加鎖有一定的系統開銷

2.Cocoa NSOperation

優點:不需要關心線程管理,數據同步的事情,可以把精力放在自己需要執行的操作上。

Cocoa operation 相關的類是 NSOperation ,NSOperationQueue。

NSOperation是個抽象類,使用它必須用它的子類,可以實現它或者使用它定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。

創建NSOperation子類的對象,把對象添加到NSOperationQueue隊列里執行。

3.GCD

Grand Central Dispatch (GCD)是Apple開發的一個多核編程的解決方法。GCD是一個替代諸如NSThread, NSOperationQueue, NSInvocationOperation等技術的很高效和強大的技術。

二,使用

(一).NSThread

兩種創建方式

1、[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];

2、NSThread* myThread = [[NSThread alloc] initWithTarget:self

selector:@selector(doSomething:)

object:nil];

[myThread start];

參數的意義:

selector :線程執行的方法,這個selector只能有一個參數,而且不能有返回值。

target? :selector消息發送的對象

argument:傳輸給target的唯一參數,也可以是nil

第一種方式會直接創建線程并且開始運行線程,第二種方式是先創建線程對象,然后再運行線程操作,在運行線程操作前可以設置線程的優先級等線程信息

不顯式創建線程的方法:

用NSObject的類方法? performSelectorInBackground:withObject: 創建一個線程:

1

[Obj performSelectorInBackground:@selector(doSomething) withObject:nil];

(二)Cocoa NSOperation的使用

使用 NSOperation的方式有兩種,

一種是用定義好的兩個子類:NSInvocationOperation 和 NSBlockOperation。

另一種是繼承NSOperation

如果你也熟悉Java,NSOperation就和java.lang.Runnable接口很相似。和Java的Runnable一樣,NSOperation也是設計用來擴展的,只需繼承重寫NSOperation的一個方法main。相當與java 中Runnalbe的Run方法。然后把NSOperation子類的對象放入NSOperationQueue隊列中,該隊列就會啟動并開始處理它。

第二種方式繼承NSOperation

在.m文件中實現main方法,main方法編寫要執行的代碼即可。

如何控制線程池中的線程數?

隊列里可以加入很多個NSOperation, 可以把NSOperationQueue看作一個線程池,可往線程池中添加操作(NSOperation)到隊列中。線程池中的線程可看作消費者,從隊列中取走操作,并執行它。

通過下面的代碼設置:

1

[queue setMaxConcurrentOperationCount:5];

線程池中的線程數,也就是并發操作數。默認情況下是-1,-1表示沒有限制,這樣會同時運行隊列中的全部的操作。

(三)GCD的介紹和使用

介紹:

Grand Central Dispatch 簡稱(GCD)是蘋果公司開發的技術,以優化的應用程序支持多核心處理器和其他的對稱多處理系統的系統。這建立在任務并行執行的線程池模式的基礎上的。它首次發布在Mac OS X 10.6 ,iOS 4及以上也可用。

設計:

GCD的工作原理是:讓程序平行排隊的特定任務,根據可用的處理資源,安排他們在任何可用的處理器核心上執行任務。

一個任務可以是一個函數(function)或者是一個block。 GCD的底層依然是用線程實現,不過這樣可以讓程序員不用關注實現的細節。

GCD中的FIFO隊列稱為dispatch queue,它可以保證先進來的任務先得到執行。

dispatch queue分為下面三種:

Serial

又稱為private dispatch queues,同時只執行一個任務。Serial queue通常用于同步訪問特定的資源或數據。當你創建多個Serial queue時,雖然它們各自是同步執行的,但Serial queue與Serial queue之間是并發執行的。

Concurrent

又稱為global dispatch queue,可以并發地執行多個任務,但是執行完成的順序是隨機的。

Main dispatch queue

它是全局可用的serial queue,它是在應用程序主線程上執行任務的。

我們看看dispatch queue如何使用?

1、常用的方法dispatch_async

為了避免界面在處理耗時的操作時卡死,比如讀取網絡數據,IO,數據庫讀寫等,我們會在另外一個線程中處理這些操作,然后通知主線程更新界面。

用GCD實現這個流程的操作比前面介紹的NSThread? NSOperation的方法都要簡單。代碼框架結構如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

// 耗時的操作

dispatch_async(dispatch_get_main_queue(), ^{

// 更新界面

});

});

如果這樣還不清晰的話,那我們還是用上兩篇博客中的下載圖片為例子,代碼如下:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"];

NSData * data = [[NSData alloc]initWithContentsOfURL:url];

UIImage *image = [[UIImage alloc]initWithData:data];

if (data != nil) {

dispatch_async(dispatch_get_main_queue(), ^{

self.imageView.image = image;

});

}

});

是不是代碼比NSThread? NSOperation簡潔很多,而且GCD會自動根據任務在多核處理器上分配資源,優化程序。

系統給每一個應用程序提供了三個concurrent dispatch queues。這三個并發調度隊列是全局的,它們只有優先級的不同。因為是全局的,我們不需要去創建。我們只需要通過使用函數dispath_get_global_queue去得到隊列,如下:

1

dispatch_queue_t globalQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

這里也用到了系統默認就有一個串行隊列main_queue:

1

dispatch_queue_t mainQ = dispatch_get_main_queue();

雖然dispatch queue是引用計數的對象,但是以上兩個都是全局的隊列,不用retain或release。

2、dispatch_group_async的使用

dispatch_group_async可以實現監聽一組任務是否完成,完成后得到通知執行其他的操作。這個方法很有用,比如你執行三個下載任務,當三個任務都下載完成后你才通知界面說完成的了。下面是一段例子代碼:

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{

[NSThread sleepForTimeInterval:1];

NSLog(@"group1");

});

dispatch_group_async(group, queue, ^{

[NSThread sleepForTimeInterval:2];

NSLog(@"group2");

});

dispatch_group_async(group, queue, ^{

[NSThread sleepForTimeInterval:3];

NSLog(@"group3");

});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{

NSLog(@"updateUi");

});

dispatch_release(group);

dispatch_group_async是異步的方法,運行后可以看到打印結果:

2012-09-25 16:04:16.737 gcdTest[43328:11303] group1

2012-09-25 16:04:17.738 gcdTest[43328:12a1b] group2

2012-09-25 16:04:18.738 gcdTest[43328:13003] group3

2012-09-25 16:04:18.739 gcdTest[43328:f803] updateUi

每個一秒打印一個,當第三個任務執行后,upadteUi被打印。

3、dispatch_barrier_async的使用

dispatch_barrier_async是在前面的任務執行結束后它才執行,而且它后面的任務等它執行完成之后才會執行

例子代碼如下:


dispatch_queue_t queue = dispatch_queue_create("gcdtest.rongfzh.yc", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:2];

NSLog(@"dispatch_async1");

});

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:4];

NSLog(@"dispatch_async2");

});

dispatch_barrier_async(queue, ^{

NSLog(@"dispatch_barrier_async");

[NSThread sleepForTimeInterval:4];

});

dispatch_async(queue, ^{

[NSThread sleepForTimeInterval:1];

NSLog(@"dispatch_async3");

});

打印結果:

2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2

2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async

2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3

請注意執行的時間,可以看到執行的順序如上所述。

4、dispatch_apply

執行某個代碼片段N次。


dispatch_apply(5, globalQ, ^(size_t index) {

// 執行5次

});

本篇使用的到的例子代碼:http://download.csdn.net/detail/totogo2010/4596471

GCD還有很多其他用法,可以參考官方文檔、http://en.wikipedia.org/wiki/Grand_Central_Dispatch

文章原址http://blog.jobbole.com/69019/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容