barrier是栅栏的意思,gcd的栅栏函数的作用:即阻挡
异步和同步的栅栏函数都有以下特点:
1、通过dispatch_barrier_(a)sync添加的block会等待前边所有的block执行完(不包括回调)才执行。
2、在其后添加的block会在dispatch_barrier_(a)sync添加的block执行完之后(不包括回调)再执行;
不同点:
1、dispatch_barrier_sync:同步栅栏函数在原线程中执行block,不开辟新线程;在将任务插入到queue的时候, dispatch_barrier_sync需要等待自己的任务结束之后才会继续程序,然后插入被写在它后面的任务。
2、dispatch_barrier_async:异步栅栏函数会开辟新线程执行block;ispatch_barrier_async将自己的任务插入到queue之后,不会等待自己的任务结束,它会继续把后面的任务插入到queue。
看下以下几个例子:
例1:示例代码testSyncBarrier方法:同步栅栏函数 + 无等待回调
{//同步栅栏函数
//并行队列
dispatch_queue_t asynQueue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(asynQueue, ^{
NSLog(@"无等待的回调任务1:%@",[NSThread currentThread]);
});
dispatch_async(asynQueue, ^{
NSLog(@"无等待的回调任务2:%@",[NSThread currentThread]);
});
NSLog(@"我在同步栅栏函数之前:%@",[NSThread currentThread]);
//同步栅栏函数
dispatch_barrier_sync(asynQueue, ^{
NSLog(@"我是无等待回调的同步栅栏函数block块:%@",[NSThread currentThread]);
});
NSLog(@"我在同步栅栏函数之后:%@",[NSThread currentThread]);
dispatch_async(asynQueue, ^{
NSLog(@"无等待的回调任务3:%@",[NSThread currentThread]);
});
dispatch_async(asynQueue, ^{
NSLog(@"无等待的回调任务4:%@",[NSThread currentThread]);
});
// {//打印
// 2018-10-24 20:24:50.158128+0800 dispatch_barrier_sync[18990:2037305] 无等待的回调任务1:<NSThread: 0x600003512800>{number = 3, name = (null)}
// 2018-10-24 20:24:50.158159+0800 dispatch_barrier_sync[18990:2037240] 我在同步栅栏函数之前:<NSThread: 0x60000354e540>{number = 1, name = main}
// 2018-10-24 20:24:50.158207+0800 dispatch_barrier_sync[18990:2037303] 无等待的回调任务2:<NSThread: 0x60000352d240>{number = 4, name = (null)}
// 2018-10-24 20:24:50.158414+0800 dispatch_barrier_sync[18990:2037240] 我是无等待回调的同步栅栏函数block块:<NSThread: 0x60000354e540>{number = 1, name = main}
// 2018-10-24 20:24:50.158544+0800 dispatch_barrier_sync[18990:2037240] 我在同步栅栏函数之后:<NSThread: 0x60000354e540>{number = 1, name = main}
// 2018-10-24 20:24:50.158704+0800 dispatch_barrier_sync[18990:2037303] 无等待的回调任务3:<NSThread: 0x60000352d240>{number = 4, name = (null)}
// 2018-10-24 20:24:50.158710+0800 dispatch_barrier_sync[18990:2037305] 无等待的回调任务4:<NSThread: 0x600003512800>{number = 3, name = (null)}
// }
//同步栅栏函数,前边的打印、栅栏函数block内的任务、后边的打印都在主线程 同步
}
例2、示例代码testAsyncBarrier方法:异步步栅栏函数 + 无等待回调
{//异步栅栏函数
//并行队列
dispatch_queue_t asynQueue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(asynQueue, ^{
NSLog(@"无等待的回调任务1:%@",[NSThread currentThread]);
});
dispatch_async(asynQueue, ^{
NSLog(@"无等待的回调任务2:%@",[NSThread currentThread]);
});
NSLog(@"我在异步步栅栏函数之前:%@",[NSThread currentThread]);
//异步栅栏函数
dispatch_barrier_async(asynQueue, ^{
NSLog(@"我是无等待回调的异步栅栏函数block块:%@",[NSThread currentThread]);
});
NSLog(@"我在异步栅栏函数之后:%@",[NSThread currentThread]);
dispatch_async(asynQueue, ^{
NSLog(@"无等待的回调任务3:%@",[NSThread currentThread]);
});
dispatch_async(asynQueue, ^{
NSLog(@"无等待的回调任务4:%@",[NSThread currentThread]);
});
// {//打印
// 2018-10-24 20:28:00.626533+0800 dispatch_barrier_sync[19060:2042379] 我在异步步栅栏函数之前:<NSThread: 0x600000c113c0>{number = 1, name = main}
// 2018-10-24 20:28:00.626540+0800 dispatch_barrier_sync[19060:2042429] 无等待的回调任务2:<NSThread: 0x600000c75780>{number = 4, name = (null)}
// 2018-10-24 20:28:00.626585+0800 dispatch_barrier_sync[19060:2042431] 无等待的回调任务1:<NSThread: 0x600000c756c0>{number = 3, name = (null)}
// 2018-10-24 20:28:00.626770+0800 dispatch_barrier_sync[19060:2042379] 我在异步栅栏函数之后:<NSThread: 0x600000c113c0>{number = 1, name = main}
// 2018-10-24 20:28:00.626777+0800 dispatch_barrier_sync[19060:2042429] 我是无等待回调的异步栅栏函数block块:<NSThread: 0x600000c75780>{number = 4, name = (null)}
// 2018-10-24 20:28:00.626938+0800 dispatch_barrier_sync[19060:2042429] 无等待的回调任务3:<NSThread: 0x600000c75780>{number = 4, name = (null)}
// 2018-10-24 20:28:00.626949+0800 dispatch_barrier_sync[19060:2042431] 无等待的回调任务4:<NSThread: 0x600000c756c0>{number = 3, name = (null)}
//
// }
//异步栅栏函数,前边的打印和后边的打印都在主线程,而异步栅栏函数内的任务在子线程 异步
}
由上边两个例子可知;dispatch_barrier_async的不等待(异步)特性体现在将任务插入队列的过程,它的等待特性体现在任务真正执行的过程。
以上例1例2所有任务都不包含回调,为了进一步理解栅栏函数执行效果,把上边两个例子的任务换成耗时的图片下载任务
例3:示例代码testSyncBarrierRequest 同步栅栏函数+有回调的接口
{//同步栅栏函数+有回调的接口
//并行队列
dispatch_queue_t asynQueue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(asynQueue, ^{
NSLog(@"耗时回调任务1:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求1返回了");
}];
[task resume];
});
dispatch_async(asynQueue, ^{
NSLog(@"耗时回调任务2:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求2返回了");
}];
[task resume];
});
NSLog(@"我在同步栅栏函数之前:%@",[NSThread currentThread]);
//同步栅栏函数
dispatch_barrier_sync(asynQueue, ^{
NSLog(@"我是耗时回调的同步栅栏函数block块:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求zl返回了");
}];
[task resume];
});
NSLog(@"我在同步栅栏函数之后:%@",[NSThread currentThread]);
dispatch_async(asynQueue, ^{
NSLog(@"耗时回调任务3:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求3返回了");
}];
[task resume];
});
dispatch_async(asynQueue, ^{
NSLog(@"耗时回调任务4:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求4返回了");
}];
[task resume];
});
// {//打印
// 2018-10-24 20:40:45.701838+0800 dispatch_barrier_sync[19214:2061713] 我在同步栅栏函数之前:<NSThread: 0x600001be0e80>{number = 1, name = main}
// 2018-10-24 20:40:45.701838+0800 dispatch_barrier_sync[19214:2061779] 耗时回调任务1:<NSThread: 0x600001b89080>{number = 3, name = (null)}
// 2018-10-24 20:40:45.701838+0800 dispatch_barrier_sync[19214:2061778] 耗时回调任务2:<NSThread: 0x600001bbe900>{number = 4, name = (null)}
// 2018-10-24 20:40:45.705053+0800 dispatch_barrier_sync[19214:2061713] 我是耗时回调的同步栅栏函数block块:<NSThread: 0x600001be0e80>{number = 1, name = main}
// 2018-10-24 20:40:45.705623+0800 dispatch_barrier_sync[19214:2061713] 我在同步栅栏函数之后:<NSThread: 0x600001be0e80>{number = 1, name = main}
// 2018-10-24 20:40:45.705823+0800 dispatch_barrier_sync[19214:2061778] 耗时回调任务3:<NSThread: 0x600001bbe900>{number = 4, name = (null)}
// 2018-10-24 20:40:45.705829+0800 dispatch_barrier_sync[19214:2061779] 耗时回调任务4:<NSThread: 0x600001b89080>{number = 3, name = (null)}
// 2018-10-24 20:40:45.799049+0800 dispatch_barrier_sync[19214:2061778] 请求1返回了
// 2018-10-24 20:40:45.800109+0800 dispatch_barrier_sync[19214:2061776] 请求2返回了
// 2018-10-24 20:40:45.800817+0800 dispatch_barrier_sync[19214:2061777] 请求zl返回了
// 2018-10-24 20:40:45.801467+0800 dispatch_barrier_sync[19214:2061777] 请求3返回了
// 2018-10-24 20:40:45.802519+0800 dispatch_barrier_sync[19214:2061777] 请求4返回了
//
// }
//同步栅栏函数,前边的打印、栅栏函数block内的任务、后边的打印都在主线程 同步
}
例4:示例代码testAsyncBarrierRequest //异步栅栏函数+有回调的接口
{//异步栅栏函数+有回调的接口
//并行队列
dispatch_queue_t asynQueue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(asynQueue, ^{
NSLog(@"耗时回调任务1:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求1返回了");
}];
[task resume];
});
dispatch_async(asynQueue, ^{
NSLog(@"耗时回调任务2:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求2返回了");
}];
[task resume];
});
NSLog(@"我在异步栅栏函数之前:%@",[NSThread currentThread]);
//同步栅栏函数
dispatch_barrier_async(asynQueue, ^{
NSLog(@"我是耗时回调的异步栅栏函数block块:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求zl返回了");
}];
[task resume];
});
NSLog(@"我在异步栅栏函数之后:%@",[NSThread currentThread]);
dispatch_async(asynQueue, ^{
NSLog(@"耗时回调任务3:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求3返回了");
}];
[task resume];
});
dispatch_async(asynQueue, ^{
NSLog(@"耗时回调任务4:%@",[NSThread currentThread]);
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:@"https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/static/protocol/https/home/img/qrcode/zbios_efde696.png"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
UIImage *image = [UIImage imageWithData:data];
NSLog(@"请求4返回了");
}];
[task resume];
});
// {//打印
// 2018-10-24 20:43:12.156237+0800 dispatch_barrier_sync[19254:2065765] 我在异步栅栏函数之前:<NSThread: 0x6000004c13c0>{number = 1, name = main}
// 2018-10-24 20:43:12.156237+0800 dispatch_barrier_sync[19254:2065850] 耗时回调任务1:<NSThread: 0x60000049a7c0>{number = 3, name = (null)}
// 2018-10-24 20:43:12.156247+0800 dispatch_barrier_sync[19254:2065848] 耗时回调任务2:<NSThread: 0x6000004a52c0>{number = 4, name = (null)}
// 2018-10-24 20:43:12.156531+0800 dispatch_barrier_sync[19254:2065765] 我在异步栅栏函数之后:<NSThread: 0x6000004c13c0>{number = 1, name = main}
// 2018-10-24 20:43:12.162173+0800 dispatch_barrier_sync[19254:2065848] 我是耗时回调的异步栅栏函数block块:<NSThread: 0x6000004a52c0>{number = 4, name = (null)}
// 2018-10-24 20:43:12.163108+0800 dispatch_barrier_sync[19254:2065848] 耗时回调任务3:<NSThread: 0x6000004a52c0>{number = 4, name = (null)}
// 2018-10-24 20:43:12.163157+0800 dispatch_barrier_sync[19254:2065850] 耗时回调任务4:<NSThread: 0x60000049a7c0>{number = 3, name = (null)}
// 2018-10-24 20:43:12.249516+0800 dispatch_barrier_sync[19254:2065850] 请求2返回了
// 2018-10-24 20:43:12.250501+0800 dispatch_barrier_sync[19254:2065848] 请求1返回了
// 2018-10-24 20:43:12.251126+0800 dispatch_barrier_sync[19254:2065848] 请求zl返回了
// 2018-10-24 20:43:12.251694+0800 dispatch_barrier_sync[19254:2065848] 请求4返回了
// 2018-10-24 20:43:12.252295+0800 dispatch_barrier_sync[19254:2065848] 请求3返回了
// }
//异步栅栏函数,前边的打印、栅栏函数block内的任务、后边的打印都在主线程 同步
}
通过例3、例4的打印可以看出无论是同步还是异步栅栏函数,调用这个函数总是在barrier block被提交之后立即返回,不会等到block被执行。
网传栅栏函数的正确用法只能用于并行队列,用于串行或全局队列,就不能起到栅栏的作用了,此时的栅栏函数相当于同步函数dispatch_sync。
于是,我试了试一下组合:
1、同步栅栏函数 + 全局队列;通过示例代码发现:与同步栅栏函数 + 并行队列 打印效果一样。。。(在这先打个问号,有高见者情留言)
2、异步栅栏函数 + 全局队列;通过示例代码发现:与异步栅栏函数 + 并行队列 打印效果一样。。。(在这先打个问号,有高见者请留言)
3、同步栅栏函数 + 串行队列;通过示例代码发现:各任务间在同一线程,顺序执行,此处用栅栏函数无意义
4、同步栅栏函数 + 串行队列;通过示例代码发现:各任务间在同一线程,顺序执行,此处用栅栏函数无意义
栅栏函数的用途:
栅栏函数不能保证有回调的任务的执行顺序,不能用于b请求依赖a请求回调的多请求案例,只适用于内部无block的任务。可以做读写锁:1、在没有写操作时,可以任意并发读取;2、在所有读操作完成后才进行写操作,写操作不能并发,且在写操作中,不能读取;3、写操作完后,又能并发读了
示例代码: