一、概念
1、同步异步:
a、同步 dispatch_sync():同步执行会等待当前任务执行完再向下执行
b、异步 dispatch_async():不等待当前任务执行完,而是把任务提交后直接向下执行,不等待提交的任务
2、队列
a、串行队列:提交到串行队列的任务会一个一个按顺序执行,上一个任务完成后、再执行下一个
创建方式(2种一样):
1、dispatch_queue_create("tongbu", NULL)
2、dispatch_queue_create("tongbu", DISPATCH_QUEUE_SERIAL);
参数1:队列标签 参数2:队列类型(并发)
3、dispatch_get_main_queue() 主队列也是串行队列
b、并发队列:提交到并发队列的任务对并发执行,每个任务从提交的那一时刻起都会为它创建一个线
程,且无法确定哪一个任务先完成。
创建方式(2种一样):
1、dispatch_get_global_queue(0, 0)//获取系统的全局并发队列
其中,参数1 有以下可选
DISPATCH_QUEUE_PRIORITY_HIGH //2
DISPATCH_QUEUE_PRIORITY_DEFAULT //0 一般选这个即可
DISPATCH_QUEUE_PRIORITY_LOW //-2
DISPATCH_QUEUE_PRIORITY_BACKGROUND // INT16_MIN ( -32768)
2、dispatch_queue_create("tongbu", DISPATCH_QUEUE_CONCURRENT)//自己创建
参数1:队列标签 参数2:队列类型(并发)
特别提醒:dispatch_queue_create 每执行一次就会创建一个新对象,
dispatch_queue_t queue1 = dispatch_queue_create("tongbu", NULL);
dispatch_queue_t queue2= dispatch_queue_create("tongbu", NULL);
此时queue1 != queue2
所以使用时如果想要使用同一队列,一定要将其存储起来
!并发队列 执行时,并不一定会将添加到队列的任务全部一起执行,而是处理数量取决于系统的状态(CPU核数,负载。。)先执行前几个,比如一次性添加了10000个任务到并发队列,他可能由于负载原因只并发执行了第40个,当根据执行情况再并发后续任务
二、使用
同步异步与队列结合使用
连续添加十个任务
组合1:同步 + 串行
无意义,连续添加十个任务,会加一个执行一个,第一个执行完,执行加入第二个
组合2:异步 + 串行
十个任务是按顺序添加,但是由于是异步添加,不会影响 "结束"的执行,同时,队列时串行队列,所以会挨个执行
组合3:同步 + 并发
无意义,以为他会等待添加的任务完成在继续下一步
组合4:异步 + 并发
每个任务都会开启新线程去并发执行,相当于是个任务同时并发执行,且不会阻塞当前程序
三、函数方法
1、 dispatch_barrier_async
dispatch_queue_t queue = dispatch_queue_create("tongbu", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, readFile);
dispatch_async(queue, readFile);
//会等上面提交的任务完成后再去写,写完后才继续执行下面的提交任务,防止了读写竞争
dispatch_barrier_async(queue, writeFile);
dispatch_async(queue, readFile);
dispatch_async(queue, readFile);
这样,多个read不会互相影响,提高了读性能,且不影响写操作(注意上面的是并发队列)
2、挂起/恢复
注意:它的原理类似于引用计数,一个queue如果调用N次dispatch_suspend,那么要想恢复,就需要调用N次dispatch_resume才可以继续,而且dispatch_resume函数不能随意调用,只有当前队列被挂起后才可以对它使用该函数,否则会报错
dispatch_queue_t queue = dispatch_queue_create("tongbu", NULL);
dispatch_suspend(queue);//挂起队列
dispatch_resume(queue);//恢复队列
3、定时器
//dispatchQueue:该定时器任务在哪个队列执行
//intervalInSeconds: 间隔时间
//leewayInSeconds :设置为0即可
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, <#dispatchQueue#>);
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, <#intervalInSeconds#> * NSEC_PER_SEC, <#leewayInSeconds#> * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
//do something ...
});
//一次暂停对应一次开始,默认创建完成timer时是暂停的,原理见上一节
//开始(不暂停时不能随意调用)
dispatch_resume(timer);
//暂停
dispatch_suspend(timer);
//销毁
dispatch_source_cancel(_timer);
需要注意:要持有 timer 和 queue,不能让其销毁,否则定时器失效。
4、dispatch_semaphore_t 信号量
异步的向数组中添加对象会产生内存问题,需要进行锁处理,可以使用dispatch_semaphore_t信号量机制实现
- (void)test1 {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//并发队列
NSMutableArray *array = [[NSMutableArray alloc] init];
for (int i = 0; i < 10000; ++i) {
dispatch_async(queue, ^{
[array addObject:[NSNumber numberWithInteger:i]];//这里会产生内存问题
});
}
NSLog(@"完成");
}
使用dispatch_semaphore_t
- (void)test2 {
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray *array = [[NSMutableArray alloc] init];
//信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
for (int i = 0; i < 10000; ++i) {
dispatch_async(queue, ^{
//1、该函数会阻塞,等待直到semaphore计数 >= 1, 然后 内部将计数减1,然后该函数执行完返回
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//2、执行到此处时, semaphore计数为0,代表没有线程修改array
[array addObject:[NSNumber numberWithInteger:i]];
//3、处理结束,修改信号量semaphore 加1,如果有dispatch_semaphore_wait函数等待,那么最先等待的那个线程就先执行
dispatch_semaphore_signal(semaphore);
});
}
NSLog(@"完成");
}
dispatch_semaphore_t,是一个持有计数的信号
//创建信号 设置信号量总数
dispatch_semaphore_t semaphore = dispatch_semaphore_create(5);
//释放一个信号,semaphore信号计数 +1
dispatch_semaphore_signal(semaphore);
//等待信号,当信号计数 >= 1 时就可以继续向下执行,同时 它将计数 进行减1 操作,,否则一直等待
//参数2 为超时时间,
//函数返回result: 0 代表success 信号计数 >=1, 非0 代表超时了,信号计数 <1
long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
适用于有限资源的访问限制
5、Group
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
//添加任务到组
dispatch_group_async(group, queue, ^{
NSLog(@"任务1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"任务2");
});
dispatch_group_async(group, queue, ^{
NSLog(@"任务3");
[NSThread sleepForTimeInterval:5];
});
//任务1,2,3都执行完后才执行该任务
dispatch_group_notify(group, queue, ^{
NSLog(@"最后打印");
});
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);
//wait函数会阻塞当前线程,直到超时或者group提前执行完成,也可以将等待时间设置为DISPATCH_TIME_NOW,立即返回结果,不会阻塞
// result: 0 代表已完成, 非0 未完成,已超时
long result = dispatch_group_wait(group, time);
NSLog(@"%ld", result);
6、dispatch_apply
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//按指定次数将block追加到queue
//会阻塞当前线程,等待任务完成
dispatch_apply(10, queue, ^(size_t i) {
NSLog(@"%zu", i);
});
NSLog(@"最后打印");