前言
當有個需求鹊碍,A,B異步請求完成之后才能請求C,D厌殉。A,B,C,D都是異步請求侈咕。這個用dispatch_group也可以實現(xiàn)公罕,只不過比dispatch_barrier麻煩一點。大家可以嘗試用dispatch_group實現(xiàn)一下耀销,這樣能更高的理解dispatch_group楼眷。還以使用dispatch_barrier來實現(xiàn)多讀單寫的功能,下面來看看dispatch_barrier怎么來實現(xiàn)這個需求熊尉。
dispatch_barrier
dispatch_barrier 作用就是相當于柵欄罐柳,柵欄前不管多少個異步都要執(zhí)行完畢,才會執(zhí)行柵欄后面的操作狰住。
-
dispatch_barrier_sync
- 提交一個柵欄函數(shù)在執(zhí)行中,它會等待柵欄函數(shù)執(zhí)行完
-
dispatch_barrier_async
- 提交一個柵欄函數(shù)在異步執(zhí)行中,它會立馬返回,不需要等值返回
一张吉、dispatch_barrier_async
下面看一下兩者共同點和區(qū)別:
//barrier 之前的并行線程執(zhí)行2s,線程執(zhí)行完畢催植。
//barrier 2s barrier 后面的線程并行執(zhí)行又是兩秒 總共6s.
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"休眠1s肮蛹,執(zhí)行柵欄前的任務");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"休眠2s,執(zhí)行柵欄前的任務");
});
//柵欄前所有任務執(zhí)行完畢创南,才開始執(zhí)行這個方法
dispatch_barrier_async(queue, ^{
sleep(2);
NSLog(@"執(zhí)行柵欄的任務");
});
NSLog(@"執(zhí)行柵欄后不在一個隊列方法");
//執(zhí)行完柵欄的方法伦忠,
dispatch_async(queue, ^{
sleep(1);
NSLog(@"休眠1s,執(zhí)行柵欄后的任務");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"休眠2s扰藕,執(zhí)行柵欄后的任務");
});
多次執(zhí)行打印結果如下:
休眠1s缓苛,執(zhí)行柵欄前的任務
休眠2s,執(zhí)行柵欄前的任務
執(zhí)行柵欄后不在一個隊列方法
執(zhí)行柵欄的方法
休眠1s邓深,執(zhí)行柵欄后的任務
休眠2s未桥,執(zhí)行柵欄后的任務
執(zhí)行結果表明:
- 并行執(zhí)行柵欄前的所有任務
- dispatch_barrier_async異步方法,不阻塞當前線程芥备,所以先執(zhí)行柵欄后不在一個隊列方法
- 執(zhí)行柵欄里任務
- 并行執(zhí)行柵欄后的所有任務
二冬耿、dispatch_barrier_async
//barrier 之前的并行線程執(zhí)行2s,線程執(zhí)行完畢萌壳。
//barrier 2s barrier 后面的線程并行執(zhí)行又是兩秒 總共6s.
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
sleep(1);
NSLog(@"休眠1s亦镶,執(zhí)行柵欄前的任務");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"休眠2s,執(zhí)行柵欄前的任務");
});
//柵欄前所有任務執(zhí)行完畢袱瓮,才開始執(zhí)行這個方法
dispatch_barrier_sync(queue, ^{
sleep(2);
NSLog(@"執(zhí)行柵欄的任務");
});
NSLog(@"執(zhí)行柵欄后不在一個隊列方法");
//執(zhí)行完柵欄的方法缤骨,
dispatch_async(queue, ^{
sleep(1);
NSLog(@"休眠1s,執(zhí)行柵欄后的任務");
});
dispatch_async(queue, ^{
sleep(2);
NSLog(@"休眠2s尺借,執(zhí)行柵欄后的任務");
});
多次執(zhí)行打印結果如下:
并行休眠1s绊起,執(zhí)行柵欄前的任務
并行休眠2s,執(zhí)行柵欄前的任務
執(zhí)行柵欄的方法
執(zhí)行柵欄后不在一個隊列方法
并行執(zhí)行休眠1s燎斩,執(zhí)行柵欄后的任務
并行執(zhí)行休眠2s虱歪,執(zhí)行柵欄后的任務
執(zhí)行結果表明:
- 并行執(zhí)行柵欄前的所有任務
- dispatch_barrier_sync同步,阻塞當前線程栅表,所以先執(zhí)行柵欄里任務
- 執(zhí)行柵欄后不在一個隊列方法
- 并行執(zhí)行柵欄后的任務
實現(xiàn)多讀單寫
一笋鄙、什么是多讀單寫?
可以同時有多個讀操作怪瓶,而在讀操作的時候萧落,不能有寫操作。
在寫操作的過程中洗贰,不能有其他寫操作找岖,并且在寫操作之前,讀操作都完成哆姻。
讀操作是可以并發(fā)執(zhí)行宣增,寫操作與(讀操作、其他寫操作)是互斥的矛缨。
二爹脾、實現(xiàn)多讀單寫的方式
- 加讀寫鎖(pthread_rwlock)來實現(xiàn)
#import <pthread.h>
@interface TKReadWhiteSafeDic() {
// 聲明一個讀寫鎖
pthread_rwlock_t lock;
// 定義一個并發(fā)隊列
dispatch_queue_t concurrent_queue;
// 用戶數(shù)據(jù)中心, 可能多個線程需要數(shù)據(jù)訪問
NSMutableDictionary *userCenterDic;
}
@end
// 多讀單寫模型
@implementation TKReadWhiteSafeDic
- (id)init {
self = [super init];
if (self) {
//初始化讀寫鎖
pthread_rwlock_init(&lock,NULL);
// 創(chuàng)建數(shù)據(jù)容器
userCenterDic = [NSMutableDictionary dictionary];
// 通過宏定義 DISPATCH_QUEUE_CONCURRENT 創(chuàng)建一個并發(fā)隊列
concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (id)objectForKey:(NSString *)key {
//加讀鎖
pthread_rwlock_rdlock(&_rwlock);
id obj = [userCenterDic objectForKey:key];
pthread_rwlock_unlock(&_rwlock);
return obj;
}
- (void)setObject:(id)obj forKey:(NSString *)key {
//加寫鎖
pthread_rwlock_wrlock(&_rwlock);
[userCenterDic setObject:obj forKey:key];
pthread_rwlock_unlock(&_rwlock);
}
- 使用dispatch_barrie來實現(xiàn)。
@interface TKReadWhiteSafeDic() {
// 定義一個并發(fā)隊列
dispatch_queue_t concurrent_queue;
// 用戶數(shù)據(jù)中心, 可能多個線程需要數(shù)據(jù)訪問
NSMutableDictionary *userCenterDic;
}
@end
// 多讀單寫模型
@implementation TKReadWhiteSafeDic
- (id)init {
self = [super init];
if (self) {
// 通過宏定義 DISPATCH_QUEUE_CONCURRENT 創(chuàng)建一個并發(fā)隊列
concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);
// 創(chuàng)建數(shù)據(jù)容器
userCenterDic = [NSMutableDictionary dictionary];
}
return self;
}
- (id)objectForKey:(NSString *)key {
__block id obj;
// 同步讀取指定數(shù)據(jù)
dispatch_sync(concurrent_queue, ^{
obj = [userCenterDic objectForKey:key];
});
return obj;
}
- (void)setObject:(id)obj forKey:(NSString *)key {
// 異步柵欄調(diào)用設置數(shù)據(jù)
dispatch_barrier_async(concurrent_queue, ^{
[userCenterDic setObject:obj forKey:key];
});
}
多讀單寫的兩個困惑點解釋一下:
- 讀操作為啥同步dispatch_sync
讀的話通常都是直接想要結果箕昭,需要同步返回結果灵妨,如果是異步獲取的話就根網(wǎng)絡請求一樣了。
- 寫操作為啥異步dispatch_barrier_async
寫操作是因為不需要等待寫操作完成落竹,所以用異步泌霍。
結尾
這個大家可以自己琢磨,做做Demo對dispatch_barrier能有更好的理解述召。