最大并发数: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>