組合 Block 的 Dispatch Group
dispatch group
可以把并行執(zhí)行的多個任務(wù)合成一組,于是調(diào)用者就可以知道這些任務(wù)何時才能全部執(zhí)行完畢穴吹。例如,可以把一系列操作文件的任務(wù)或者網(wǎng)絡(luò)請求的任務(wù)添加到 dispatch group
中嗜侮,等全部完成這些耗時的任務(wù)之后再進行下一步操作港令。
創(chuàng)建 dispatch group
的方式如下:
dispatch_group_t dispatch_group_create(void);
dispatch group
就是個簡單的數(shù)據(jù)結(jié)構(gòu),這種結(jié)構(gòu)彼此之間沒有什么區(qū)別锈颗,它不像派發(fā)隊列顷霹,后者還有個用來區(qū)別身份的標識符。
想把任務(wù)編組击吱,有兩種方法淋淀。第一種是用下面這個函數(shù):
dispatch_group_async(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block);
它是普通 dispatch_async
函數(shù)的變體。group
參數(shù)用于表示執(zhí)行的塊所歸屬的組覆醇,queue
表示執(zhí)行任務(wù)的隊列朵纷。所以 dispatch_group_async
可以方便的向 dispatch group
中添加不同隊列的不同任務(wù)。此函數(shù)中的 queue
既可以時串行隊列永脓,又可以時并行隊列袍辞。然而,如果所有任務(wù)都排在同一個串行隊列里常摧,那么 dispatch group
的用處就不大了搅吁,因為只需要在提交完全部任務(wù)之后再提交一個塊即可。
第二種能夠指定任務(wù)所屬的 dispatch group
的方法是使用下面這一對函數(shù):
void dispatch_group_enter(dispatch_group_t group);
void dispatch_group_leave(dispatch_group_t group);
前者能夠使 dispatch group
里正要執(zhí)行的任務(wù)數(shù)遞增落午,而后者則使之遞減谎懦。所以,調(diào)用完 dispatch_group_enter
以后溃斋,必須有與之對應(yīng)的 dispatch_group_leave
才行界拦。如果調(diào)用 enter
之后,沒有相應(yīng)的 leave
操作梗劫,那么這一組任務(wù)就永遠執(zhí)行不完享甸。在使用時,可以在向隊列中添加任務(wù)時調(diào)用 enter
在跳,在任務(wù)執(zhí)行完成之后合適的地方調(diào)用 leave
枪萄。
當(dāng)像 group
中添加完所有的任務(wù)之后,有兩種方式可以等待任務(wù)完成猫妙。第一種方法是使用下面的函數(shù):
long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);
此函數(shù)有兩個參數(shù)瓷翻,group
是要等待的線程組,timeout
表示要等待的時間。timeout
參數(shù)表示函數(shù)在等待 dispatch group
執(zhí)行完畢時齐帚,應(yīng)該阻塞多久妒牙。如果執(zhí)行 dispatch group
所需的時間小于 timeout
,則返回 0对妄,否則返回非 0 值湘今。此參數(shù)也可以取常量 DISPATCH_TIME_FOREVER
,這表示函數(shù)會一直等待 dispatch group
執(zhí)行完剪菱,而不會超時摩瞎。注意:dispatch_group_wait
是同步的,會阻塞當(dāng)前線程孝常,所以不能放在主線程執(zhí)行旗们。
第二種方式時使用下面函數(shù):
void dispatch_group_notify(dispatch_group_t group,
dispatch_queue_t queue,
dispatch_block_t block);
與 dispatch_group_wait
不同的是該函數(shù)不會阻塞當(dāng)前線程。開發(fā)著可以向此函數(shù)傳入 block
构灸,等 dispatch group
執(zhí)行完畢之后上渴,block
會在指定的線程上運行。
使用 dispatch_group_wait
的例子:
- object-c
NSLog(@"--- 開始設(shè)置任務(wù) ----");
// 因為 dispatch_group_wait 會阻塞線程喜颁,所以創(chuàng)建一個新的線程稠氮,用來完成任務(wù)
// 同時用異步的方式向新線程(tasksQueue)中添加任務(wù)
dispatch_queue_t tasksQueue = dispatch_queue_create("tasksQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(tasksQueue, ^{
// 真正用來完成任務(wù)的線程
dispatch_queue_t performTasksQueue = dispatch_queue_create("performTasksQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
for (int i = 0; i < 3; i++) {
// 入組之后的 block 會被 group 監(jiān)聽
// 注意:dispatch_group_enter 一定和 dispatch_group_leave 要配對出現(xiàn)
dispatch_group_enter(group);
dispatch_async(performTasksQueue, ^{
NSLog(@"開始第 %zd 項任務(wù)", i);
[NSThread sleepForTimeInterval:(3 - i)];
dispatch_group_leave(group);
NSLog(@"完成第 %zd 項任務(wù)", i);
});
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"全部任務(wù)完成");
});
});
NSLog(@"--- 結(jié)束設(shè)置任務(wù) ----");
- swift 3.0
print("--- 開始設(shè)置任務(wù) ----");
DispatchQueue.main.async {
let group = DispatchGroup.init()
let tasksQueue = DispatchQueue.init(label: "tasksQueue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
for i in 0..<3 {
group.enter()
tasksQueue.async {
print("開始第 \(i) 項任務(wù)")
sleep(UInt32(3 - i))
print("結(jié)束第 \(i) 項任務(wù)")
group.leave()
}
}
//
let result = group.wait(timeout: DispatchTime.distantFuture)
if result == .success {
print("全部任務(wù)完成")
} else {
print("任務(wù)執(zhí)行超時")
}
}
print("--- 開始設(shè)置任務(wù) ----");
輸出如下:
--- 開始設(shè)置任務(wù) ----
--- 結(jié)束設(shè)置任務(wù) ----
開始第 0 項任務(wù)
開始第 1 項任務(wù)
開始第 2 項任務(wù)
完成第 2 項任務(wù)
完成第 1 項任務(wù)
完成第 0 項任務(wù)
全部任務(wù)完成