最大併發數:ios
什麼是併發數?併發
同時執行的任務數。好比同時開啓三個線程執行三個任務,併發數就是3.app
最大併發數相關的方法:異步
-(NSInteger)maxConcurrentOperationCount;ide
-(void)setMaxConcurrentOperationCount:(NSInteger)cnt;atom
剖析最大併發數:併發數就是同時執行操做的數量,並非只線程的個數。就是指同時執行任務的個數,當一個線程執行完畢後會有一個回收到線程池的過程,這時若是線程池中還有別的線程就會直接拿出來進行任務的執行。若是線程池中沒有線程,就會等待回收後的線程。spa
注:最大線程個數是由CPU內核決定的線程
GCD與NSOPeration的線程的不一樣之處code
1。咱們知道GCD的線程大致可分爲六大中,同步串行隊列(不開闢線程),同步並行隊列(開闢線程),異步串行隊列(開闢線程),異步並行隊列(開闢線程),主隊列, 全局隊列。對象
可是咱們知道開闢線程和耗費內存,而GCD中方法雖多,可是不少咱們開闢線程並無意義,反而會耗費內存。NSOPeration實際上是對GCD中的一個封裝,可是他並無封裝GCD中全部的方法。NSOperationQueue建立出來的對象至關於異步並行隊列,NSInvocationOperation若有start這至關於同步串行隊列。NSBlockOperation將建立的對象加到NSOperationQueue建立隊列中,至關一異步串行
NSOperationQueue * q = [NSOperationQueue mainQueue]至關於GCD的主隊列
2.隊列的取消、暫停、和恢復NSOPeration有,GCD是沒有的
取消隊列的全部操做
-(void)cancelAllOperations;
提示:也能夠調用NSOperation的-(void)cancel方法取消單個操做。
暫停和恢復隊列
-(void)setSuspended:(BOOL)b; // YES表示暫停隊列 NO表示恢復隊列
-(BOOL)isSuspend;
獲取隊列操做數:
operationCount(只讀屬性)
注意:
(1)暫停不會刪除隊列內的操做。只是把隊列掛起。暫停和掛起都是針對隊列而言的。暫停後還能夠從新恢復接着原來的任務進行執行。
(2)取消所有任務的操做會清空隊列裏的全部任務。
(3)暫停和取消都是對隊列裏的操做而言的,而正在執行的操做是沒法取消或暫停的。
在實際的開發中:一般定義一個全局的操做隊列, 而後就能夠把全部的任務都添加進去。在開發中須要注意的兩點:
(1)在用戶點擊」暫停/繼續」的按鈕觸發的事件中,須要先判斷當前隊列內是否有任務,若是全局隊列內沒有任務就直接return返回,從而沒有任務的時候不會改變隊列的掛起和恢復狀態。
(2)在用戶點擊」取消所有操做」的按鈕觸發的事件中,取消操做以後須要重置全局隊列爲恢復狀態,這樣無論原先全局隊列的狀態如何,在取消所有操做以後又從新置於初始狀態。從而不會影響新的操做。
代碼
- (void) viewDidLoad { self.view.backgroundColor = [UIColor whiteColor]; UIButton * downButton = [UIButton buttonWithType:UIButtonTypeCustom]; downButton.frame = CGRectMake(20, 80, 200, 60); [downButton setBackgroundColor:[UIColor greenColor]]; [downButton addTarget:self action:@selector(download) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:downButton]; } - (void) download { if (self.opQueue.operationCount == 0) { NSLog(@"沒有操做"); return; } //暫停,繼續 self.opQueue.suspended = !self.opQueue.suspended; if (self.opQueue.suspended) { NSLog(@"暫停"); } else { NSLog(@"繼續"); } } - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { // [self opDemo1]; // [self opDemo2]; // [self opDemo3]; // [self opDemo4]; [self opDemo5]; } //懶加載 - (NSOperationQueue *)opQueue { if(_opQueue == nil) { _opQueue = [[NSOperationQueue alloc] init]; } return _opQueue; } #pragma mark - 線程間通訊 - (void) opDemo5 { self.opQueue = [[NSOperationQueue alloc] init];
//maxConcurrentOperationCount 必需要設,否者暫停不了
//我的理解,若不設置最大併發數,則全部任務併發執行,而暫停操做只能暫停還沒開始的任務。下載中的任務不會暫停
//maxCincurrentOpertaionCount爲多少,暫停下載後。就會有多少任務下載完成,由於點擊暫停時,還有這麼多人物在執行中 self.opQueue.maxConcurrentOperationCount = 1; NSLog(@"+1"); for (int i = 0; i < 500; i ++) { NSOperation * op = [NSBlockOperation blockOperationWithBlock:^{ [NSThread sleepForTimeInterval:1]; NSLog(@"%d 耗時操做 ===== %@", i,[NSThread currentThread]); }]; [self.opQueue addOperation:op]; } NSLog(@"+3"); }
NSOperation之間能夠設置依賴來保證執行順序,這是GCD所不具有的功能:
好比必定要讓操做A執行完後,才能執行操做B,能夠這麼寫:
[operationB addDependency:operationA]; // 操做B依賴於操做
- 具體使用:將任務(block)添加到隊列(串行/併發(全局)),指定執行任務的方法(同步(阻塞)/異步)
- 線程通訊:獲取主線程dispatch_get_main_queue()。在主線程更新UI
- 還有NSOperation沒法作到的事:一次性執行,延遲執行,調度組(NSOperation相對複雜)
NSOperation ---->ios2.0(後來改造了NSOperation的底層)
- 具體使用:將操做(異步執行的)添加到隊列(併發/全局)。其實就是封裝了GCD裏的異步執行全局或併發隊列。
- 線程通訊: [[NSOperationQueue mainQueue] addOperation:op3];拿到主隊列,往主隊列添加操做(更新UI)
- 提供了一些GCD沒法實現的功能:「最大併發數」
- 暫停/繼續 -------掛起
- 取消全部任務
- 依賴關係
1 <span style="font-size:18px;">// 2 // ViewController.m 3 // NSOperation之線程間通訊 4 // 5 // Created by apple on 15/10/22. 6 // Copyright (c) 2015年 LiuXun. All rights reserved. 7 // 8 9 #import "ViewController.h" 10 11 @interface ViewController () 12 /** 13 通常開發中,會定義一個全局的隊列。整個程序均可以把操做往裏面放。 14 負責調度全部的操做 15 */ 16 @property(nonatomic, strong) NSOperationQueue *opQueue; 17 @end 18 19 @implementation ViewController 20 21 /** 22 小結: 23 只要是NSOperation的子類,就能添加到操做隊列 24 - 一旦操做添加到隊列, 就會自動異步執行 25 - 若是沒有添加到隊列, 而是使用start方法,就會在當前線程執行操做 26 - 若是是線程間通訊, 可使用[NSOperaionQueue mainQueue] 拿到主隊列,往主隊列添加操做(更新UI) 27 */ 28 29 /** 30 GCD----> ios4.0 31 - 具體使用:將任務(block)添加到隊列 (串行/併發(全局)) ,指定執行任務的方法(同步(阻塞)/異步) 32 - 線程通訊:獲取主線程dispatch_get_main_queue()。在主線程更新UI 33 - 還有NSOperation沒法作到的事:一次性執行,延遲執行,調度組(NSOperation相對複雜) 34 35 NSOperation ---->ios2.0 (後來改造了NSOperation的底層) 36 - 具體使用:將操做(異步執行的)添加到隊列(併發/全局)。其實就是封裝了GCD裏的異步執行全局或併發隊列。 37 - 線程通訊: [[NSOperationQueue mainQueue] addOperation:op3];拿到主隊列,往主隊列添加操做(更新UI) 38 - 提供了一些GCD沒法實現的功能:「最大併發數」 39 - 暫停/繼續 ------- 掛起 40 - 取消全部任務 41 - 依賴關係 42 */ 43 44 /** 45 懶加載的方式,初始化NSOperationQueue對象 46 */ 47 -(NSOperationQueue *)opQueue 48 { 49 if(_opQueue == nil) 50 { 51 _opQueue = [[NSOperationQueue alloc] init]; 52 } 53 return _opQueue; 54 } 55 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 56 { 57 [self dependcy]; 58 } 59 #pragma mark - 線程間通訊(很是重要) 60 -(void)opDemo1 61 { 62 NSOperationQueue *q = [[NSOperationQueue alloc] init]; 63 [q addOperationWithBlock:^{ 64 NSLog(@"耗時操做......%@", [NSThread currentThread]); 65 66 // 在主線程更新UI 67 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 68 NSLog(@"更新UI......%@", [NSThread currentThread]); 69 }]; 70 }]; 71 } 72 73 #pragma mark- 最大併發數 74 /** 75 注意:最大併發數不是說線程的數量,而是說同時進行操做的數量 76 */ 77 -(void)opDemo2 78 { 79 self.opQueue.maxConcurrentOperationCount = 2; 80 for(int i=0; i<10 ; i++){ 81 NSOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 82 [NSThread sleepForTimeInterval:1.0]; 83 NSLog(@"%@------%d", [NSThread currentThread], i); 84 }]; 85 [self.opQueue addOperation:op]; 86 } 87 } 88 89 #pragma mark - 高級操做 掛起 90 // 就是暫停和繼續: 對隊列的操做 91 /** 92 應用場景:好比當咱們在有WiFi的地發用手機下載電影,可是有事情走開了,斷網了電影只下載了一半,這時就須要掛起,等到了有網的地方又能夠接着原來的進度下載。 93 切記:掛起的是隊列,不會影響已經在執行的操做 94 */ 95 -(IBAction)pause 96 { 97 98 // 判斷操做的數量,當前隊列裏面是否有操做 99 if(self.opQueue.operationCount == 0){ 100 NSLog(@"沒有操做"); 101 return; // 沒有操做的時候直接return,不會修改隊列的狀態 102 } 103 104 // 暫停繼續 : 105 self.opQueue.suspended = !self.opQueue.suspended; 106 if(self.opQueue.suspended){ 107 NSLog(@"暫停"); 108 }else 109 { 110 NSLog(@"繼續"); 111 } 112 } 113 114 #pragma mark- 高級操做 隊列取消 115 /** 116 取消操做並不會影響隊列的掛起狀態 117 */ 118 -(IBAction)cancel 119 { 120 // 取消隊列內的全部操做 121 // 只是取消隊列裏的任務,而正在執行的任務是沒法取消的 122 // 另外取消了任務就是刪除了隊列內的全部操做 123 [self.opQueue cancelAllOperations]; 124 NSLog(@"取消全部操做"); 125 126 // 取消隊列的掛起狀態(只要是取消了隊列的操做,咱們就把隊列處於一個啓動狀態,以便於後續的開始) 127 self.opQueue.suspended = NO; 128 } 129 130 #pragma mark -依賴關係 131 -(void)dependcy 132 { 133 /** 134 舉例場景: 135 1. 下載一個小說的壓縮包 136 2. 解壓縮,刪除壓縮包 137 3. 更新UI 138 */ 139 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ 140 NSLog(@"下載一個小說的壓縮包,%@",[NSThread currentThread]); 141 }]; 142 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ 143 NSLog(@"解壓縮,刪除壓縮包,%@",[NSThread currentThread]); 144 }]; 145 NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ 146 NSLog(@"更新UI,%@",[NSThread currentThread]); 147 }]; 148 // 若是直接把任務添加到隊裏,會異步執行,使順序錯亂 149 150 // 所以須要指定任務之間的依賴關係--------依賴關係能夠跨隊列(能夠在子線程下載完,到主線程更新UI) 151 [op2 addDependency:op1]; // op2 依賴於op1 就是執行op2以前必須先執行op1 152 [op3 addDependency:op2]; // op3 依賴於op2 就是執行op3以前必須先執行op2 153 154 /** 155 千萬注意:不要形成相互依賴即依賴循環,會形成死鎖 156 */ 157 // [op1 addDependency:op3]; 158 159 160 // waitUntilFinished 相似於GCD中調度組的通知 161 // NO表示不等待當前的隊列執行完畢,就執行下面的代碼,打印 NSLog(@"任務完成"); 162 // YES 表示必須等隊列內的任務所有執行完畢才執行下面的代碼 163 [ self.opQueue addOperations:@[op1, op2] waitUntilFinished:YES]; 164 165 // 在主線程更新UI 166 [[NSOperationQueue mainQueue] addOperation:op3]; 167 168 NSLog(@"任務完成"); 169 } 170 @end 171 </span>