四、最大并发数
最大并发数是NSOperation特有的
1、什么是并发数
同时执行的任务数
比如,同时开3个线程执行3个任务,并发数就是3
2、最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
(1)设置队列的最大并发(操作)数
// 设置队列的最大并发数,队列是负责调度操作的 self.queue.maxConcurrentOperationCount = 2; for (int i = 0; i < 10; i++) { [self.queue addOperationWithBlock:^{ // 模拟休眠 [NSThread sleepForTimeInterval:1.0f]; NSLog(@"正在下载 %@ %d", [NSThread currentThread], i); }]; }
输出结果:
正在下载 <NSThread: 0x8e2a260>{name = (null), num = 3} 0
正在下载 <NSThread: 0x8d1f920>{name = (null), num = 2} 1
正在下载 <NSThread: 0x8d1f920>{name = (null), num = 2} 3
正在下载 <NSThread: 0x8e2a260>{name = (null), num = 3} 2
正在下载 <NSThread: 0x8e2a260>{name = (null), num = 3} 5
正在下载 <NSThread: 0x8d1f920>{name = (null), num = 2} 4
正在下载 <NSThread: 0x8e2a260>{name = (null), num = 3} 6
正在下载 <NSThread: 0x8d1f920>{name = (null), num = 2} 7
正在下载 <NSThread: 0x8d1f920>{name = (null), num = 2} 9
正在下载 <NSThread: 0x8e2a260>{name = (null), num = 3} 8
结果说明,开启了2条子线程,每次调用2条线程执行任务。
maxConcurrentOperationCount 如果== 3,结果是:
最大并发数是3,实际运行过程中,使用到4条线程,每次调用3条线程执行任务。
所以,最大并发数是每次最多调用子线程的数量。具体在哪条线程上工作,是由系统分配的。
maxConcurrentOperationCount 如果== 1,结果是:
结果说明,如果 最大并发数 == 1类似于串行队列异步方法
(2)执行块中设置最大并发数
// 实例化block操作 NSBlockOperation *op = [[NSBlockOperation alloc] init]; // 添加执行块 [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]); }]; self.queue.maxConcurrentOperationCount = 2; [self.queue addOperation:op];
输出结果:
从结果看出,设置最大并发数不会限制执行块。一定要注意
3、最大并发数的应用场景
(1)用户在使用3G的时候
限制线程的数量,省电,省流量(省钱)
(2)用户使用WIFI的时候(局域网)
增加线程数量,提高用户的体验
五、队列的取消、暂停、恢复
1、取消队列的所有操作
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
2、暂停和恢复队列
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
六、操作优先级
没事儿不要改优先级
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
七、操作依赖
1、NSOperation之间可以设置依赖来保证执行顺序
比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA]; // 操作B依赖于操作A
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(@"更新书架(UI),提示用户可以阅读 。。。 %@", [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];
输出结果:
正在下载图书。。。 <NSThread: 0x8c18b40>{name = (null), num = 2}
正在解压缩图书。。。 <NSThread: 0x8c18b40>{name = (null), num = 2}
正在保存到磁盘。。。 <NSThread: 0x8c18b40>{name = (null), num = 2}
更新书架(UI),提示用户可以阅读。。。 <NSThread: 0x8e19030>{name = (null), num = 1}
结果说明,操作依赖类似于串行队列,异步执行。
2、可以在不同queue的NSOperation之间创建依赖关系
3、注意:不能相互依赖,比如A依赖B,B依赖A
八、操作监听
- (void (^)(void))completionBlock;
- (void)setCompletionBlock:(void (^)(void))block;
九、自定义NSOperation的步骤很简单
1、重写- (void)main方法,在里面实现想执行的任务
重写- (void)main方法的注意点
2、自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应