標籤:多線程 nsoperation gcd 並發 nsoperation queue
NSOperation是蘋果封裝的一套多線程的東西,不像GCD是純C語言的,這個是OC的。但相比較之下GCD會更快一些,但本質上NSOPeration是多GDC的封裝。
一、NSOperation與GCD的比較
GCD是基於c的底層api,NSOperation屬於object-c類。ios首先引入的是NSOperation,IOS4之後引入了GCD和NSOperationQueue並且其內部是用gcd實現的。
GCD優點:GCD主要與block結合使用。代碼簡潔高效。執行效率稍微高點。
NSOperation相對於GCD:
1,NSOperation擁有更多的函數可用,具體查看api。NSOperationQueue 是在GCD基礎上實現的,只不過是GCD更高一層的抽象。
2,在NSOperationQueue中,可以建立各個NSOperation之間的依賴關係。
3,NSOperationQueue支援KVO。可以監測operation是否正在執行(isExecuted)、是否結束(isFinished),是否取消(isCanceld)
4,GCD 只支援FIFO 的隊列,而NSOperationQueue可以調整隊列的執行順序(通過調整權重)。NSOperationQueue可以方便的管理並發、NSOperation之間的優先順序。
使用NSOperation的情況:各個操作之間有依賴關係、操作需要取消暫停、並發管理、控制操作之間優先順序,限制同時能執行的線程數量.讓線程在某時刻停止/繼續等。
使用GCD的情況:一般的需求很簡單的多線程操作,用GCD都可以了,簡單高效。
從編程原則來說,一般我們需要儘可能的使用高等級、封裝完美的API,在必須時才使用底層API。
當需求簡單,簡潔的GCD或許是個更好的選擇,而Operation queue 為我們提供能更多的選擇。
二、NSOperation的簡單操作
?NSOperation(操作)配NSoperationQueue(隊列)來實現多線程.?沒有像GCD一樣串列並行什麼的, 直接拿來就能用.
?操作依賴:NSOperation可以通過設定依賴來保證執行順序.某一個操作的執行, 必須等待另一個操作完成才會繼續執行.
使用:[op1 addDependency:op2] 依賴關係可以跨隊列指定的.(不能弄成循環相依性)
?可以指定隊列的優先順序。
使用NSOperation的方法(3者是等價的
):(注意NSOperation是抽象類別, 必須使用他的子類才能實現)
?方法1、用NSOperation的子類NSInvocationOperation來建立操作.
?方法2、用NSOperation的子類NSBlockOperation來建立操作. (與前者效果一樣)
?方法3、直接弄個隊列(可以是主隊列,先跑起來),再addOperationWithBlock更加簡便.
?方法4、直接自訂NSOperation,實現相應的方法。
實現NSOperation的方法,以及掛起、暫停,設定最大並發數,設定依賴關係等。
@interface XNViewController ()/** NSOperation操作隊列 */@property (nonatomic, strong) NSOperationQueue *queue;@end@implementation XNViewController// 將操作添加到隊列即可- (NSOperationQueue *)queue{ if (!_queue) _queue = [[NSOperationQueue alloc] init]; return _queue;}/** ============================= 暫停掛起 ============================= *//** 暫停操作 */- (IBAction)pause{ // 1. 判斷隊列中是否有操作 if (self.queue.operationCount == 0) { NSLog(@"沒有操作"); return; } // 2. 如果沒有被掛起(正在執行),才需要暫停 // 只會掛起當前隊列中還沒有被調度(沒有被安排到線程上工作的操作)才會被掛起 if (!self.queue.isSuspended) { NSLog(@"暫停"); [self.queue setSuspended:YES]; } else { NSLog(@"已經暫停"); }}/** 繼續操作 */- (IBAction)resume{ // 1. 判斷隊列中是否有操作 if (self.queue.operationCount == 0) { NSLog(@"沒有操作"); return; } // 2. 如果有被擱置動作,才需要繼續(恢複) if (self.queue.isSuspended) { NSLog(@"繼續"); [self.queue setSuspended:NO]; } else { NSLog(@"正在執行"); }}/** ========================NSOperation指定操作之間的依賴關係========================*/- (void)opDemo6{ NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"正在下載蒼老師全集 。。。 %@", [NSThread currentThread]); }]; NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"正在解壓縮蒼老師全集。。。 %@", [NSThread currentThread]); }]; NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"正在儲存到磁碟 。。。 %@", [NSThread currentThread]); }]; NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下載完成 。 %@", [NSThread currentThread]); }]; // 指定操作之間的”依賴“關係,某一個操作的執行,必須等待另一個操作完成才會開始 // 依賴關係是可以跨隊列指定的 [op2 addDependency:op1]; [op3 addDependency:op2]; [op4 addDependency:op3]; // *** 添加依賴的時候,注意不要出現循環相依性// [op3 addDependency:op4]; [self.queue addOperation:op1]; [self.queue addOperation:op2]; [self.queue addOperation:op3]; // 主隊列更新UI [[NSOperationQueue mainQueue] addOperation:op4];}/** ==================================設定最大並發數==================================== */- (void)opDemo5{ // 設定隊列的最大並發數,隊列是負責調度操作的 /** 最大並發數的應用情境: 1> 使用者在使用3G的時候 限制線程的數量,省電,省流量(省錢) 2> 使用者使用WIFI的時候(區域網路) 增加線程數量,提高使用者的體驗 maxConcurrentOperationCount 如果== 1,類似於串列隊列非同步方法呼叫 */ self.queue.maxConcurrentOperationCount = 1; for (int i = 0; i < 10; i++) { [self.queue addOperationWithBlock:^{ NSLog(@"正在下載 %@ %d", [NSThread currentThread], i); }]; }}/** ============================= Block操作,添加執行塊 ============================= */- (void)opDemo4{ // 執行個體化block操作 NSBlockOperation *op = [[NSBlockOperation alloc] init]; // 設定最大並發(操作)數,不會限制執行塊! self.queue.maxConcurrentOperationCount = 2; // 添加執行塊 [op addExecutionBlock:^{ NSLog(@"下載蒼老師全集1 %@", [NSThread currentThread]); }]; // 繼續添加塊 [op addExecutionBlock:^{ NSLog(@"下載蒼老師全集2 %@", [NSThread currentThread]); }]; // 繼續添加塊 [op addExecutionBlock:^{ NSLog(@"下載蒼老師全集3 %@", [NSThread currentThread]); }]; // 繼續添加塊 [op addExecutionBlock:^{ NSLog(@"下載蒼老師全集4 %@", [NSThread currentThread]); }]; // 繼續添加塊 [op addExecutionBlock:^{ NSLog(@"下載蒼老師全集5 %@", [NSThread currentThread]); }]; // 啟動操作,在主線程執行 // 如果執行塊的數量超過1,就會自動進入其他線程執行(非同步) // 具體開啟線程的數量,由系統決定 // 執行塊的調度與操作的調度非常像// [op start]; [self.queue addOperation:op];}/** ============================= 直接添加塊操作 ============================= */- (void)opDemo3{ // 只要將操作添加到隊列就會立即被調度(執行) for (int i = 0; i < 10; i++) { [self.queue addOperationWithBlock:^{ NSLog(@"下載開始 %@ - %@", [NSThread currentThread], @(i)); }]; } // 向主隊列中添加操作 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"下載開始 %@ - %@", [NSThread currentThread], nil); }];}/**============================= NSBlockOperation =============================*/- (void)opDemo2{ for (int i = 0; i < 10; i++) { // 指定一個塊操作 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下載開始 %@ - %@", [NSThread currentThread], @(i)); }]; // 將塊操作添加到隊列. 新開線程 [self.queue addOperation:op1]; }}/** =============================NSInvocationOperation============================= */- (void)opDemo1{ for (int i = 0; i < 10; i++) { NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download:) object:@(i)]; // 如果直接啟動,會在主線程執行 // [op1 start]; // 添加到隊列,就會建立線程,非同步執行 [self.queue addOperation:op1]; }}- (void)download:(id)obj{ NSLog(@"下載開始 %@ - %@", [NSThread currentThread], obj);}@end
自訂NSOperation:1、繼承NSOperation2、重新main方法
@interface XNMyOperation : NSOperation@end//============================上為.h標頭檔,下為.m檔案=============================@implementation XNMyOperation// 只要重寫main就可以了- (void)main{ // 自訂動作,一定要自己添加自動釋放池 @autoreleasepool { //。。。。。。。。。。。 }}@end
參考:
http://jianshu.io/p/d09e2638eb27
http://blog.csdn.net/hufengvip/article/details/11806897
http://blog.csdn.net/vieri_ch/article/details/21937859
apple官方文檔
轉載請註明出處:http://blog.csdn.net/xn4545945