先列一下本篇文章所整理的提綱
1.GCD的延遲運行
2.使用Dispatch_group進行線程同步處理
3.使用dispatch_barrier函數(shù)(柵欄函數(shù))給訪問對象加同步鎖
4.同步執(zhí)行隊列函數(shù)dispatch_sync
5.使用dispatch_apply遍歷數(shù)組執(zhí)行任務
一湖雹、GCD延遲執(zhí)行
我們在工作中有可能回碰到需要延遲執(zhí)行某些命令的需求。在學習GCD之前我們可以通過
[self performSelector:@selector(abc:) withObject:nil afterDelay:2];
來延遲執(zhí)行某些任務棚瘟。但是使用這些方法有一些不方便的地方雅镊。首先可以帶的參數(shù)比較少。第二就是在不同線程中執(zhí)行的時候不如GCD方便殷勘。
使用GCD的方法如下椰苟、
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"test");
});
方法講解:1.參數(shù)dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)代表從當前的時間延遲3s后執(zhí)行
DISPATCH_TIME_NOW代表從當前時間磁餐。
類似的還有DISPATCH_TIME_FOREVER這個通常用在等待某些方法執(zhí)行完成的時候使用例如dispatch_wait函數(shù)來判斷添加到隊列中的任務是否已經完成。
2.參數(shù)2決定在什么隊列中執(zhí)行要添加到隊列中的任務幼衰。本例中代表被添加的輸出test字符串在主線程中運行靴跛。
二、dispatch_group函數(shù)
使用場景:項目中的任務執(zhí)行在很多情況下是有順序的渡嚣。例如對任務B對數(shù)據(jù)進行緩存執(zhí)行之前梢睛。可能需要調用兩個數(shù)據(jù)請求獲得數(shù)據(jù)X和數(shù)據(jù)Y识椰。當數(shù)據(jù)X和Y同時完成了數(shù)據(jù)請求之后绝葡。才能執(zhí)行任務B。我們自然可以使用串行隊列裤唠。按照X->Y->B的任務添加順序去執(zhí)行任務。但是某些任務可能非常耗時莹痢。這樣會浪費大量的時間种蘸。而且不能有效的利用系統(tǒng)提供的多線程技術來加快任務的執(zhí)行速度。這顯然是不合適的竞膳。在這種情況下Dispatc_group就排上用場了航瞭。
我們可以使用多線程取獲取X和Y然后當X、Y都完成的時候再去執(zhí)行B坦辟。
使用代碼如下:
dispatch_queue_t queueGlobal = dispatch_queue_create("globalQueue", DISPATCH_QUEUE_CONCURRENT);
//創(chuàng)建一個并行隊列
dispatch_group_t groupBase = dispatch_group_create();
//創(chuàng)建一個Dispatch_group
dispatch_group_async(groupBase, queueGlobal, ^{
//任務X
for (NSInteger i = 0; i < 10; i++){
if (i == 9) NSLog(@"X馬上執(zhí)行完成");
}
});
//異步將任務X添加到groupBase的queueGlobal隊列上
dispatch_group_async(groupBase, queueGlobal, ^{
//任務Y
for (NSInteger i = 0; i < 10; i++){
if (i == 9) NSLog(@"Y馬上執(zhí)行完成");
}
});
//異步將任務Y添加到groupBase的queueGlobal隊列上
dispatch_group_notify(groupBase, queueGlobal, ^{
//任務B
NSLog(@"B任務開始執(zhí)行");
});
//等待groupBase上的任務執(zhí)行完成的時候執(zhí)行任務B
調試輸出框輸出為
2018-01-17 23:14:14.592177+0800 GCD二[16104:486560] X馬上執(zhí)行完成
2018-01-17 23:14:14.593407+0800 GCD二[16104:486558] Y馬上執(zhí)行完成
2018-01-17 23:14:14.601304+0800 GCD二[16104:486560] B任務開始執(zhí)行
通過以上我們可以清晰的分析得出刊侯。通過dispatch_group可以對并行隊列進行線程同步處理
(2)dispatch_group_wait函數(shù)分析
等待dispatch_group執(zhí)行完成除了可以使用dispatch_group_notify還可以使用dispatch_group_wait函數(shù)。使用如下
dispatch_queue_t queueGlobal = dispatch_queue_create("globalQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t groupBase = dispatch_group_create();
dispatch_group_async(groupBase, queueGlobal, ^{
//任務X
for (NSInteger i = 0; i < 10; i++){
if (i == 9) NSLog(@"X馬上執(zhí)行完成");
}
});
dispatch_group_async(groupBase, queueGlobal, ^{
//任務Y
for (NSInteger i = 0; i < 10; i++){
if (i == 9) NSLog(@"Y馬上執(zhí)行完成");
}
});
BOOL isComplete = dispatch_group_wait(groupBase, DISPATCH_TIME_FOREVER);
NSLog(@"%d",isComplete);
調試輸出為
2018-01-17 23:20:16.809152+0800 GCD二[16145:489420] Y馬上執(zhí)行完成
2018-01-17 23:20:16.809152+0800 GCD二[16145:489418] X馬上執(zhí)行完成
2018-01-17 23:20:16.812577+0800 GCD二[16145:489332] 0
DISPATCH_TIME_FOREVER代表一直等待下去直到dispatch_group中的任務執(zhí)行完成锉走。等待期間執(zhí)行dispatch_group_wait函數(shù)的線程(當前線程)會一直被堵塞滨彻。而dispatch_group_notify則不會。所以我們平時在使用中還是多使用dispatch_group_notify函數(shù)比較好挪蹭。
三亭饵、dispatch_barrier_async柵欄函數(shù)的使用
在運行一些耗時操作的時候。使用多線程技術我們可以極大的提高我們的任務執(zhí)行效率梁厉。但是使用多線程技術也會帶來一些問題辜羊。比如對一些數(shù)據(jù)進行寫入操作。
1.對同一個數(shù)據(jù)不能夠同時執(zhí)行兩次寫入操作,
2.在進行寫入過程的時候能夠加上同步鎖词顾。拒絕執(zhí)行讀取操作八秃。
但是我們又不想舍棄多線程技術。在這種情景下dispatch_barrier_async函數(shù)就派上用上了肉盹。
使用如下:
objectA.h
#import <Foundation/Foundation.h>
@interface ObjectA : NSObject
@property (nonatomic, copy) NSString *baseString;
@end
ViewController.m
ObjectA *object = [[ObjectA alloc]init];
object.baseString = @"testABC";
dispatch_queue_t globalDefaultQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
for (NSInteger i = 0; i < 20; i++){
dispatch_async(globalDefaultQueue, ^{
NSLog(@"%@ --- %ld",object.baseString,i);
});
if (i == 10){
dispatch_barrier_async(globalDefaultQueue, ^{
object.baseString = @"ABC";
});
}
}
執(zhí)行結果如下:
2018-01-17 23:35:01.010879+0800 GCD二[16289:497032] testABC --- 10
2018-01-17 23:35:01.008748+0800 GCD二[16289:497017] testABC --- 2
2018-01-17 23:35:01.008760+0800 GCD二[16289:497016] testABC --- 3
2018-01-17 23:35:01.008921+0800 GCD二[16289:497025] testABC --- 4
2018-01-17 23:35:01.009424+0800 GCD二[16289:497026] testABC --- 5
2018-01-17 23:35:01.009437+0800 GCD二[16289:497027] testABC --- 6
2018-01-17 23:35:01.009864+0800 GCD二[16289:497029] testABC --- 7
2018-01-17 23:35:01.010640+0800 GCD二[16289:497031] testABC --- 8
2018-01-17 23:35:01.010659+0800 GCD二[16289:497030] testABC --- 9
2018-01-17 23:35:01.008200+0800 GCD二[16289:497015] testABC --- 0
2018-01-17 23:35:01.008227+0800 GCD二[16289:497014] testABC --- 1
2018-01-17 23:35:01.011883+0800 GCD二[16289:497033] ABC --- 11
2018-01-17 23:35:01.012994+0800 GCD二[16289:497034] ABC --- 12
2018-01-17 23:35:01.013015+0800 GCD二[16289:497035] ABC --- 13
2018-01-17 23:35:01.013565+0800 GCD二[16289:497036] ABC --- 14
2018-01-17 23:35:01.014066+0800 GCD二[16289:497037] ABC --- 15
2018-01-17 23:35:01.014870+0800 GCD二[16289:497038] ABC --- 16
2018-01-17 23:35:01.029353+0800 GCD二[16289:497039] ABC --- 17
2018-01-17 23:35:01.030392+0800 GCD二[16289:497040] ABC --- 18
2018-01-17 23:35:01.030875+0800 GCD二[16289:497041] ABC --- 19
我們可以得出結論昔驱。在同一個線程中通過柵欄函數(shù)執(zhí)行的時候∩先蹋可以自動同步鎖防止在進行寫入數(shù)據(jù)的時候對同一個數(shù)據(jù)讀取舍悯。保證了數(shù)據(jù)的正確性航棱。