GCD介绍(一): 基本概念和Dispatch Queue (转载)
Grand Central Dispatch或者GCD,是一套低層API,提供了一種新的方法來(lái)進(jìn)行并發(fā)程序編寫。從基本功能上講,GCD有點(diǎn)像 NSOperationQueue,他們都允許程序?qū)⑷蝿?wù)切分為多個(gè)單一任務(wù)然后提交至工作隊(duì)列來(lái)并發(fā)地或者串行地執(zhí)行。GCD比之 NSOpertionQueue更底層更高效,并且它不是Cocoa框架的一部分。
除了代碼的平行執(zhí)行能力,GCD還提供高度集成的事件控制系統(tǒng)。可以設(shè)置句柄來(lái)響應(yīng)文件描述符、mach ports(Mach port?用于 OS X上的進(jìn)程間通訊)、進(jìn)程、計(jì)時(shí)器、信號(hào)、用戶生成事件。這些句柄通過(guò)GCD來(lái)并發(fā)執(zhí)行。
GCD的API很大程度上基于block,當(dāng)然,GCD也可以脫離block來(lái)使用,比如使用傳統(tǒng)c機(jī)制提供函數(shù)指針和上下文指針。實(shí)踐證明,當(dāng)配合block使用時(shí),GCD非常簡(jiǎn)單易用且能發(fā)揮其最大能力。
你可以在Mac上敲命令“man dispatch”來(lái)獲取GCD的文檔。
為何使用?
GCD提供很多超越傳統(tǒng)多線程編程的優(yōu)勢(shì):
Dispatch Objects
盡管GCD是純c語(yǔ)言的,但它被組建成面向?qū)ο蟮娘L(fēng)格。GCD對(duì)象被稱為dispatch object。Dispatch object像Cocoa對(duì)象一樣是引用計(jì)數(shù)的。使用dispatch_release和dispatch_retain函數(shù)來(lái)操作dispatch object的引用計(jì)數(shù)來(lái)進(jìn)行內(nèi)存管理。但主意不像Cocoa對(duì)象,dispatch object并不參與垃圾回收系統(tǒng),所以即使開啟了GC,你也必須手動(dòng)管理GCD對(duì)象的內(nèi)存。
Dispatch queues 和 dispatch sources(后面會(huì)介紹到)可以被掛起和恢復(fù),可以有一個(gè)相關(guān)聯(lián)的任意上下文指針,可以有一個(gè)相關(guān)聯(lián)的任務(wù)完成觸發(fā)函數(shù)。可以查閱“man dispatch_object”來(lái)獲取這些功能的更多信息。
Dispatch Queues
GCD的基本概念就是dispatch queue。dispatch queue是一個(gè)對(duì)象,它可以接受任務(wù),并將任務(wù)以先到先執(zhí)行的順序來(lái)執(zhí)行。dispatch queue可以是并發(fā)的或串行的。并發(fā)任務(wù)會(huì)像NSOperationQueue那樣基于系統(tǒng)負(fù)載來(lái)合適地并發(fā)進(jìn)行,串行隊(duì)列同一時(shí)間只執(zhí)行單一任務(wù)。
GCD中有三種隊(duì)列類型:
創(chuàng)建隊(duì)列
要使用用戶隊(duì)列,我們首先得創(chuàng)建一個(gè)。調(diào)用函數(shù)dispatch_queue_create就行了。函數(shù)的第一個(gè)參數(shù)是一個(gè)標(biāo)簽,這純是為了 debug。Apple建議我們使用倒置域名來(lái)命名隊(duì)列,比如“com.dreamingwish.subsystem.task”。這些名字會(huì)在崩潰日 志中被顯示出來(lái),也可以被調(diào)試器調(diào)用,這在調(diào)試中會(huì)很有用。第二個(gè)參數(shù)目前還不支持,傳入NULL就行了。
提交 Job
向一個(gè)隊(duì)列提交Job很簡(jiǎn)單:調(diào)用dispatch_async函數(shù),傳入一個(gè)隊(duì)列和一個(gè)block。隊(duì)列會(huì)在輪到這個(gè)block執(zhí)行時(shí)執(zhí)行這個(gè)block的代碼。下面的例子是一個(gè)在后臺(tái)執(zhí)行一個(gè)巨長(zhǎng)的任務(wù):
| 1 2 3 4 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ ????????[self goDoSomethingLongAndInvolved]; ????????NSLog(@"Done doing something long and involved"); }); |
dispatch_async?函數(shù)會(huì)立即返回, block會(huì)在后臺(tái)異步執(zhí)行。?
當(dāng)然,通常,任務(wù)完成時(shí)簡(jiǎn)單地NSLog個(gè)消息不是個(gè)事兒。在典型的Cocoa程序中,你很有可能希望在任務(wù)完成時(shí)更新界面,這就意味著需要在主線 程中執(zhí)行一些代碼。你可以簡(jiǎn)單地完成這個(gè)任務(wù)——使用嵌套的dispatch,在外層中執(zhí)行后臺(tái)任務(wù),在內(nèi)層中將任務(wù)dispatch到main queue:
| 1 2 3 4 5 6 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ ????????[self goDoSomethingLongAndInvolved]; ????????dispatch_async(dispatch_get_main_queue(), ^{ ????????????[textField setStringValue:@"Done doing something long and involved"]; ????????}); }); |
還有一個(gè)函數(shù)叫dispatch_sync,它干的事兒和dispatch_async相同,但是它會(huì)等待block中的代碼執(zhí)行完成并返回。結(jié)合 __block類型修飾符,可以用來(lái)從執(zhí)行中的block獲取一個(gè)值。例如,你可能有一段代碼在后臺(tái)執(zhí)行,而它需要從界面控制層獲取一個(gè)值。那么你可以使 用dispatch_sync簡(jiǎn)單辦到:
| 1 2 3 4 5 6 7 8 | __block NSString *stringValue; dispatch_sync(dispatch_get_main_queue(), ^{ ????????// __block variables aren't automatically retained ????????// so we'd better make sure we have a reference we can keep ????????stringValue = [[textField stringValue] copy]; }); [stringValue autorelease]; // use stringValue in the background now |
我們還可以使用更好的方法來(lái)完成這件事——使用更“異步”的風(fēng)格。不同于取界面層的值時(shí)要阻塞后臺(tái)線程,你可以使用嵌套的block來(lái)中止后臺(tái)線程,然后從主線程中獲取值,然后再將后期處理提交至后臺(tái)線程:
dispatch_queue_t bgQueue = myQueue;dispatch_async(dispatch_get_main_queue(), ^{NSString *stringValue = [[[textField stringValue] copy] autorelease];dispatch_async(bgQueue, ^{// use stringValue in the background now});});取決于你的需求,myQueue可以是用戶隊(duì)列也可以使全局隊(duì)列。
?
不再使用鎖(Lock)
用戶隊(duì)列可以用于替代鎖來(lái)完成同步機(jī)制。在傳統(tǒng)多線程編程中,你可能有一個(gè)對(duì)象要被多個(gè)線程使用,你需要一個(gè)鎖來(lái)保護(hù)這個(gè)對(duì)象:
NSLock *lock;訪問(wèn)代碼會(huì)像這樣:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | - (id)something { ????id localSomething; ????[lock lock]; ????localSomething = [[something retain] autorelease]; ????[lock unlock]; ????return localSomething; } - (void)setSomething:(id)newSomething { ????[lock lock]; ????if(newSomething != something) ????{ ????????[something release]; ????????something = [newSomething retain]; ????????[self updateSomethingCaches]; ????} ????[lock unlock]; } |
使用GCD,可以使用queue來(lái)替代:
dispatch_queue_t queue;要用于同步機(jī)制,queue必須是一個(gè)用戶隊(duì)列,而非全局隊(duì)列,所以使用usingdispatch_queue_create初始化一個(gè)。然后可以用dispatch_async?或者?dispatch_sync將共享數(shù)據(jù)的訪問(wèn)代碼封裝起來(lái):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | - (id)something { ????__block id localSomething; ????dispatch_sync(queue, ^{ ????????localSomething = [something retain]; ????}); ????return [localSomething autorelease]; } - (void)setSomething:(id)newSomething { ????dispatch_async(queue, ^{ ????????if(newSomething != something) ????????{ ????????????[something release]; ????????????something = [newSomething retain]; ????????????[self updateSomethingCaches]; ????????} ????}); } |
?值得注意的是dispatch queue是非常輕量級(jí)的,所以你可以大用特用,就像你以前使用lock一樣。
現(xiàn)在你可能要問(wèn):“這樣很好,但是有意思嗎?我就是換了點(diǎn)代碼辦到了同一件事兒。”
實(shí)際上,使用GCD途徑有幾個(gè)好處:
總結(jié)
現(xiàn)在你已經(jīng)知道了GCD的基本概念、怎樣創(chuàng)建dispatch queue、怎樣提交Job至dispatch queue以及怎樣將隊(duì)列用作線程同步。接下來(lái)我會(huì)向你展示如何使用GCD來(lái)編寫平行執(zhí)行代碼來(lái)充分利用多核系統(tǒng)的性能^ ^。我還會(huì)討論GCD更深層的東西,包括事件系統(tǒng)和queue targeting。
?
?
原文:http://www.dreamingwish.com/dream-2012/of-of-of-of-gcd-introduced-1-basic-concepts-in-and-the-dispatch-queue.html
轉(zhuǎn)載于:https://www.cnblogs.com/liushanshan/archive/2013/02/05/2893024.html
總結(jié)
以上是生活随笔為你收集整理的GCD介绍(一): 基本概念和Dispatch Queue (转载)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Linux常用命令(整理)
- 下一篇: GCC几个选项学习