iOS 实现并发和串行任务
2017-08-24 本文已影响1289人
一只长毛猫
串行任务
场景:现有3个耗时任务A,B,C 需要依次有序执行。
分析:为了不阻塞主线程,只能异步依次执行任务A,B,C
方式一:GCD串行队列 实现串行任务
特点:只需开启一个线程,串行执行多个任务
//创建串行队列 (DISPATCH_QUEUE_SERIAL:串行) (DISPATCH_QUEUE_CONCURRENT:并发)
dispatch_queue_t queue = dispatch_queue_create("com.fw.queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"任务A thread:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"任务B thread:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"任务C thread:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"任务执行完毕,回到主线程 thread:%@",[NSThread currentThread]);
});
});
NSLog(@"结束");
打印结果
结束
2017-08-24 11:34:28.368057+0800 UIViewTest[27526:7523798] 结束
2017-08-24 11:34:29.376597+0800 UIViewTest[27526:7524243] 任务A thread:<NSThread: 0x170279080>{number = 5, name = (null)}
2017-08-24 11:34:30.379257+0800 UIViewTest[27526:7524243] 任务B thread:<NSThread: 0x170279080>{number = 5, name = (null)}
2017-08-24 11:34:31.384996+0800 UIViewTest[27526:7524243] 任务C thread:<NSThread: 0x170279080>{number = 5, name = (null)}
2017-08-24 11:34:31.385371+0800 UIViewTest[27526:7523798] 任务执行完毕,回到主线程 thread:<NSThread: 0x17007a240>{number = 1, name = main}
可以看出任务A,B,C 是在同一个线程中,被一次执行的。执行完毕后,又可以回到主线程。
方式二:GCD后台线程+条件锁 实现串行任务
特点:需开启多个线程,利用条件锁依次执行
NSConditionLock *lock = [[NSConditionLock alloc]initWithCondition:1];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lockWhenCondition:3];
sleep(1);
NSLog(@"任务C thread:%@",[NSThread currentThread]);
[lock unlockWithCondition:4];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lockWhenCondition:2];
sleep(1);
NSLog(@"任务B thread:%@",[NSThread currentThread]);
[lock unlockWithCondition:3];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lockWhenCondition:1];
sleep(1);
NSLog(@"任务A thread:%@",[NSThread currentThread]);
[lock unlockWithCondition:2];
});
NSLog(@"结束");
打印结果
2017-08-24 11:42:39.911399+0800 UIViewTest[27529:7528485] 结束
2017-08-24 11:42:40.919128+0800 UIViewTest[27529:7528837] 任务A thread:<NSThread: 0x170274e80>{number = 6, name = (null)}
2017-08-24 11:42:41.924922+0800 UIViewTest[27529:7528592] 任务B thread:<NSThread: 0x170274600>{number = 7, name = (null)}
2017-08-24 11:42:42.926247+0800 UIViewTest[27529:7528836] 任务C thread:<NSThread: 0x170263f00>{number = 8, name = (null)}
可以看出,任务A,B,C是按顺序执行的,每个任务都是在不同的线程中执行的。
方式三:NSOperationQueue
特点:若果添加依赖关系,那么多个任务在同一个线程中完成。如果没有依赖关系,那么多个任务在多个线程中完成
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSBlockOperation *opA = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"任务A thread:%@",[NSThread currentThread]);
}];
NSBlockOperation *opB = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"任务B thread:%@",[NSThread currentThread]);
}];
NSBlockOperation *opC = [NSBlockOperation blockOperationWithBlock:^{
sleep(1);
NSLog(@"任务C thread:%@",[NSThread currentThread]);
}];
//添加依赖关系,保证执行顺序
[opC addDependency:opB];
[opB addDependency:opA];
[queue addOperation:opB];
[queue addOperation:opC];
[queue addOperation:opA];
执行结果
2017-08-24 13:03:50.129224+0800 UIViewTest[27599:7554889] 任务A thread:<NSThread: 0x170064480>{number = 3, name = (null)}
2017-08-24 13:03:51.132080+0800 UIViewTest[27599:7554889] 任务B thread:<NSThread: 0x170064480>{number = 3, name = (null)}
2017-08-24 13:03:52.133824+0800 UIViewTest[27599:7554889] 任务C thread:<NSThread: 0x170064480>{number = 3, name = (null)}
并发任务
特点:开启多条线程,同时执行多个任务。
方式一:采用dispatch_group,可以获取所有任务执行完毕的通知
场景:同时执行三个任务,所有任务执行完毕后,调用者可以得到通知。
dispatch_group是GCD的一项特性,能够给任务分组。调用者可以等待这组任务执行完毕,也可以在提供回调函数之后继续往下执行。这组任务完成时,调用者会得到通知。
//创建分组
dispatch_group_t dispatchGroup = dispatch_group_create();
//获取队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//添加并发任务
for (int i=1; i<=3; i++) {
dispatch_group_async(dispatchGroup, queue, ^{
sleep(1);
NSLog(@"任务%d thread:%@",i,[NSThread currentThread]);
});
}
//任务执行完毕后,获取通知
dispatch_group_notify(dispatchGroup, queue, ^{
NSLog(@"执行完毕 thread:%@",[NSThread currentThread]);
});
打印结果
2017-08-24 14:15:26.971016+0800 UIViewTest[27661:7571605] 任务1 thread:<NSThread: 0x170070d40>{number = 3, name = (null)}
2017-08-24 14:15:26.971405+0800 UIViewTest[27661:7571541] 任务2 thread:<NSThread: 0x170070d00>{number = 4, name = (null)}
2017-08-24 14:15:26.971735+0800 UIViewTest[27661:7571606] 任务3 thread:<NSThread: 0x170064440>{number = 5, name = (null)}
2017-08-24 14:15:26.971984+0800 UIViewTest[27661:7571606] 执行完毕 thread:<NSThread: 0x170064440>{number = 5, name = (null)}
从结果可以看出,最后的一个任务3执行完毕后,接着在同一个线程里,通知了调用者,所有任务执行完毕。
方式二:利用并发队列,直接执行并发任务
特点:不能获取所有任务执行完毕的通知
//串行:DISPATCH_QUEUE_SERIAL
//并发 DISPATCH_QUEUE_CONCURRENT
dispatch_queue_t queue = dispatch_queue_create("com.fw.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"任务A thread:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"任务B thread:%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
sleep(1);
NSLog(@"任务C thread:%@",[NSThread currentThread]);
});
NSLog(@"结束");
上面代码中的queue 也可以用GCD常用后台线程替换
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
打印结果
2017-08-24 14:33:35.523264+0800 UIViewTest[27666:7575286] 结束
2017-08-24 14:33:36.530702+0800 UIViewTest[27666:7575315] 任务A thread:<NSThread: 0x17026f240>{number = 3, name = (null)}
2017-08-24 14:33:36.531057+0800 UIViewTest[27666:7575311] 任务B thread:<NSThread: 0x17026f280>{number = 4, name = (null)}
2017-08-24 14:33:36.531344+0800 UIViewTest[27666:7575314] 任务C thread:<NSThread: 0x17026f180>{number = 5, name = (null)}
可以看出三个任务,都在同一时刻完成