iOS開發 多線程(三)轉自MJ的NSOperationQueue使用

1、簡介java

一個NSOperation對象能夠經過調用start方法來執行任務,默認是同步執行的。也能夠將NSOperation添加到一個NSOperationQueue(操做隊列)中去執行,並且是異步執行的。併發

建立一個操做隊列:異步

[java] view plaincopy性能

  1. NSOperationQueue *queue = [[NSOperationQueue alloc] init];  spa


2、添加NSOperationNSOperationQueue.net

1.添加一個operation線程

[java] view plaincopy設計

  1. [queue addOperation:operation];  3d


2.添加一組operationorm

[java] view plaincopy

  1. [queue addOperations:operations waitUntilFinished:NO];  


3.添加一個block形式的operation

[java] view plaincopy

  1. [queue addOperationWithBlock:^() {  

  2.     NSLog(@"執行一個新的操做,線程:%@", [NSThread currentThread]);  

  3. }];  


NSOperation添加到queue以後,一般短期內就會獲得運行。可是若是存在依賴,或者整個queue被暫停等緣由,也可能須要等待。

注意:NSOperation添加到queue以後,絕對不要再修改NSOperation對象的狀態。由於NSOperation對象可能會在任什麼時候候運行,所以改變NSOperation對象的依賴或數據會產生不利的影響。你只能查看NSOperation對象的狀態, 好比是否正在運行、等待運行、已經完成等


3、添加NSOperation的依賴對象
1.當某個NSOperation對象依賴於其它NSOperation對象的完成時,就能夠經過addDependency方法添加一個或者多個依賴的對象,只有全部依賴的對象都已經完成操做,當前NSOperation對象纔會開始執行操做。另外,經過removeDependency方法來刪除依賴對象。

[java] view plaincopy

  1. [operation2 addDependency:operation1];  

依賴關係不侷限於相同queue中的NSOperation對象,NSOperation對象會管理本身的依賴, 所以徹底能夠在不一樣的queue之間的NSOperation對象建立依賴關係


惟一的限制是不能建立環形依賴,好比A依賴B,B依賴A,這是錯誤的


2.依賴關係會影響到NSOperation對象在queue中的執行順序,看下面的例子:

1> 沒有設置依賴關係

[java] view plaincopy

  1. NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

  2.   

  3. NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){  

  4.     NSLog(@"執行第1次操做,線程:%@", [NSThread currentThread]);  

  5. }];  

  6.   

  7. NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){  

  8.     NSLog(@"執行第2次操做,線程:%@", [NSThread currentThread]);  

  9. }];  

  10.   

  11. [queue addOperation:operation1];  

  12. [queue addOperation:operation2];  

打印信息:

[java] view plaincopy

  1. 2013-02-03 00:21:35.024 thread[5616:3d13] 執行第1次操做,線程:<NSThread: 0x7658570>{name = (null), num = 3}  

  2. 2013-02-03 00:21:35.063 thread[5616:1303] 執行第2次操做,線程:<NSThread: 0x765a2e0>{name = (null), num = 4}  

能夠看出,默認是按照添加順序執行的,先執行operation1,再執行operation2

2> 設置了依賴關係

[java] view plaincopy

  1. NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

  2.   

  3. NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){  

  4.     NSLog(@"執行第1次操做,線程:%@", [NSThread currentThread]);  

  5. }];  

  6.   

  7. NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){  

  8.     NSLog(@"執行第2次操做,線程:%@", [NSThread currentThread]);  

  9. }];  

  10. // operation1依賴於operation2  

  11. [operation1 addDependency:operation2];  

  12.   

  13. [queue addOperation:operation1];  

  14. [queue addOperation:operation2];  

打印信息:

[java] view plaincopy

  1. 2013-02-03 00:24:16.260 thread[5656:1b03] 執行第2次操做,線程:<NSThread: 0x7634490>{name = (null), num = 3}  

  2. 2013-02-03 00:24:16.285 thread[5656:1303] 執行第1次操做,線程:<NSThread: 0x9138b50>{name = (null), num = 4}  

能夠看出,先執行operation2,再執行operation1

4、修改Operations的執行順序

對於添加到queue中的operations,它們的執行順序取決於2點:

1.首先看看NSOperation是否已經準備好:是否準備好由對象的依賴關係肯定

2.而後再根據全部NSOperation的相對優先級來肯定。優先級等級則是operation對象自己的一個屬性。默認全部operation都擁有「普通」優先級,不過能夠經過setQueuePriority:方法來提高或下降operation對象的優先級。優先級只能應用於相同queue中的operations。若是應用有多個operation queue,每一個queue的優先級等級是互相獨立的。所以不一樣queue中的低優先級操做仍然可能比高優先級操做更早執行。

注意:優先級不能替代依賴關係,優先級只是對已經準備好的 operations肯定執行順序。先知足依賴關係,而後再根據優先級從全部準備好的操做中選擇優先級最高的那個執行。


5、設置隊列的最大併發操做數量

隊列的最大併發操做數量,意思是隊列中最多同時運行幾條線程

雖然NSOperationQueue類設計用於併發執行Operations,你也能夠強制單個queue一次只能執行一個Operation。setMaxConcurrentOperationCount:方法能夠配置queue的最大併發操做數量。設爲1就表示queue每次只能執行一個操做。不過operation執行的順序仍然依賴於其它因素,好比operation是否準備好和operation的優先級等。所以串行化的operation queue並不等同於GCD中的串行dispatch queue

[java] view plaincopy

  1. // 每次只能執行一個操做  

  2. queue.maxConcurrentOperationCount = 1;  

  3. // 或者這樣寫  

  4. [queue setMaxConcurrentOperationCount:1];  


6、取消Operations

一旦添加到operation queue,queue就擁有了這個Operation對象而且不能被刪除,惟一能作的事情是取消。你能夠調用Operation對象的cancel方法取消單個操做,也能夠調用operation queue的cancelAllOperations方法取消當前queue中的全部操做。

[java] view plaincopy

  1. // 取消單個操做  

  2. [operation cancel];  

  3.   

  4. // 取消queue中全部的操做  

  5. [queue cancelAllOperations];  


7、等待Options完成

爲了最佳的性能,你應該設計你的應用盡量地異步操做,讓應用在Operation正在執行時能夠去處理其它事情。若是須要在當前線程中處理operation完成後的結果,可使用NSOperation的waitUntilFinished方法阻塞當前線程,等待operation完成。一般咱們應該避免編寫這樣的代碼,阻塞當前線程多是一種簡便的解決方案,可是它引入了更多的串行代碼,限制了整個應用的併發性,同時也下降了用戶體驗。絕對不要在應用主線程中等待一個Operation,只能在第二或次要線程中等待。阻塞主線程將致使應用沒法響應用戶事件,應用也將表現爲無響應。

[java] view plaincopy

  1. // 會阻塞當前線程,等到某個operation執行完畢  

  2. [operation waitUntilFinished];  


除了等待單個Operation完成,你也能夠同時等待一個queue中的全部操做,使用NSOperationQueue的waitUntilAllOperationsAreFinished方法。注意:在等待一個 queue時,應用的其它線程仍然能夠往queue中添加Operation,所以可能會加長線程的等待時間。

[java] view plaincopy

  1. // 阻塞當前線程,等待queue的全部操做執行完畢  

  2. [queue waitUntilAllOperationsAreFinished];  


8、暫停和繼續queue

若是你想臨時暫停Operations的執行,可使用queue的setSuspended:方法暫停queue。不過暫停一個queue不會致使正在執行的operation在任務中途暫停,只是簡單地阻止調度新Operation執行。你能夠在響應用戶請求時,暫停一個queue來暫停等待中的任務。稍後根據用戶的請求,能夠再次調用setSuspended:方法繼續queue中operation的執行

[java] view plaincopy

  1. // 暫停queue  

  2. [queue setSuspended:YES];  

  3.   

  4. // 繼續queue  

  5. [queue setSuspended:NO];  

相關文章
相關標籤/搜索