//聯(lián)系人:石虎QQ:1224614774昵稱:嗡嘛呢叭咪哄
一、GCD 分發(fā)隊(duì)列
GCD 分發(fā)隊(duì)列是執(zhí)行任務(wù)的有力工具。使用分發(fā)隊(duì)列,你可以異步或者阻塞執(zhí)行任意多個(gè) block 的代碼。你可以使用分發(fā)隊(duì)列來執(zhí)行幾乎任何線程任務(wù)。GCD 提供了簡單易用的接口。
二、在 GCD 中存在三種隊(duì)列:
1串行分發(fā)隊(duì)列(Serial dispatch queue)
串行分發(fā)隊(duì)列又被稱為私有分發(fā)隊(duì)列,按順序執(zhí)行隊(duì)列中的任務(wù),且同一時(shí)間只執(zhí)行一個(gè)任務(wù)。串行分發(fā)隊(duì)列常用于實(shí)現(xiàn)同步鎖。下面代碼創(chuàng)建了一個(gè)串行分發(fā)隊(duì)列:
dispatch_queue_t serialQueue = dispatch_queue_create("com.example.MyQueue",NULL);
2并發(fā)分發(fā)隊(duì)列(Concurrent dispatch queue)
串行分發(fā)隊(duì)列又被稱為全局分發(fā)隊(duì)列,也按順序執(zhí)行隊(duì)列中的任務(wù),但是順序開始的多個(gè)任務(wù)會(huì)并發(fā)同時(shí)執(zhí)行。并發(fā)分發(fā)隊(duì)列常用于管理并發(fā)任務(wù)。下面代碼創(chuàng)建了一個(gè)并發(fā)分發(fā)隊(duì)列:
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
3主分發(fā)隊(duì)列(Main dispatch queue)
主分發(fā)隊(duì)列是一個(gè)全局唯一的特殊的串行分發(fā)隊(duì)列。隊(duì)列中的任務(wù)會(huì)被在應(yīng)用的主線程中執(zhí)行。主分發(fā)隊(duì)列可以用于執(zhí)行 UI 相關(guān)的操作。取得主分發(fā)隊(duì)列的方法:
dispatch_queue_t mainQueue = dispatch_get_main_queue();
GCD 任務(wù)執(zhí)行方式
GCD 中有兩種任務(wù)執(zhí)行方式:
異步執(zhí)行, dispatch_async,意味將任務(wù)放入隊(duì)列之后,主線程不會(huì)等待 block 的返回結(jié)果,而是立即繼續(xù)執(zhí)行下去。
阻塞執(zhí)行, dispatch_sync,意味將任務(wù)放入隊(duì)列之后,主線程被阻塞,需要等待 block 的執(zhí)行結(jié)果返回,才能繼續(xù)執(zhí)行下去。
GCD 的其他主題
GCD 有著豐富的功能,比如分發(fā)組(dispatch group),信號(hào)(semaphores),分發(fā)柵欄(dispatch barrier),分發(fā)源(dispatch source)等等。這些可以用于完成更復(fù)雜的多線程任務(wù)。詳細(xì)可以查閱 Apple 關(guān)于 GCD 的文檔。
使用建議
在能夠使用 GCD 的地方,盡量使用 GCD
Apple 公司宣稱其在 GCD 技術(shù)中為更好地利用多核硬件系統(tǒng)做了很多的優(yōu)化。所以,在性能方面 GCD 是不用擔(dān)心的。而且 GCD 也提供了相當(dāng)豐富的 API,幾乎可以完成絕大部分線程相關(guān)的編程任務(wù)。所以,在多線程相關(guān)主題的編程中,GCD 應(yīng)該是首選。下面舉一些可以推薦使用 GCD 的實(shí)際例子:
1使用 GCD 的 dispatch queue 實(shí)現(xiàn)同步鎖
同步鎖的實(shí)現(xiàn)方案有不少,比如,如果僅僅是想對(duì)某個(gè)實(shí)例變量的讀寫操作加鎖,可以使用屬性(property)的 atomic 參數(shù),對(duì)于一段代碼加鎖可以使用@synchronized塊,或者 NSLock。
@synchronized和 NSLock 實(shí)現(xiàn)的同步鎖:
// Method 1
- (void)synchronizedMethod {
@synchronized(self) {
// safe
}
}
// Method 2
_lock = [[NSLock alloc] init];
- (void)synchronizedMethod {
[_lock lock];
// Safe
[_lock unlock];
}
@synchronized一般會(huì)以self為同步對(duì)象。重復(fù)調(diào)用@synchronized(self) 是很危險(xiǎn)的。如果多個(gè)屬性這么做,每一個(gè)屬性將會(huì)被和其它所有屬性同步,這可能并不是你所希望的,更好的方法是每個(gè)屬性的鎖都是相互獨(dú)立的。
另一種方法是使用 NSLock 實(shí)現(xiàn)同步鎖,這個(gè)方法不錯(cuò),但是缺點(diǎn)是在極端環(huán)境下同步塊可能會(huì)導(dǎo)致鎖死,而且這種情況下處理鎖死狀態(tài)會(huì)有麻煩。
一個(gè)替代方法是使用 GCD 的分發(fā)隊(duì)列。將讀和寫分發(fā)到相同并發(fā)隊(duì)列中,這樣讀操作會(huì)是并發(fā)的,多個(gè)線程可以同時(shí)執(zhí)行寫操作;而對(duì)于寫操作,以分發(fā)柵欄(dispatch barrier)保證同時(shí)只有一個(gè)線程可以執(zhí)行寫操作,并且由于寫操作無需返回,寫操作還是異步馬上返回的。這樣,就得到了一個(gè)高效且線程安全的鎖。代碼看起來會(huì)像這樣:
_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
- (NSInteger)cake {
__blockNSInteger localCake;
dispatch_sync(_syncQueue, ^{
localCake = _cake;
});
returnlocalCake;
}
- (void)setCake:(NSInteger)cake {
dispatch_barrier_async(_syncQueue, ^{
_cake = cake;
});
}
簡單而言,上面的代碼可以使讀操作被競爭執(zhí)行;寫操作被互斥執(zhí)行,并且異步返回。使用 GCD 實(shí)現(xiàn)的這個(gè)同步鎖應(yīng)該是效率最優(yōu)且最安全的。