自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

GCD介紹(一):基本概念和Dispatch Queue

移動開發(fā) iOS
本文為大家介紹GCD的基本概念和Dispatch Queue?,F(xiàn)在你需要知道GCD的基本概念,怎樣創(chuàng)建dispatch queue,怎樣提交Job至dispatch queue以及怎樣將隊列用作線程同步。

[[77402]]

什么是GCD?

Grand Central Dispatch或者GCD,是一套低層API,提供了一種新的方法來進行并發(fā)程序編寫。從基本功能上講,GCD有點像NSOperationQueue,他們都允許程序?qū)⑷蝿?wù)切分為多個單一任務(wù)然后提交至工作隊列來并發(fā)地或者串行地執(zhí)行。GCD比之NSOpertionQueue更底層更高效,并且它不是Cocoa框架的一部分。

除了代碼的平行執(zhí)行能力,GCD還提供高度集成的事件控制系統(tǒng)??梢栽O(shè)置句柄來響應(yīng)文件描述符、mach ports(Mach port 用于 OS X上的進程間通訊)、進程、計時器、信號、用戶生成事件。這些句柄通過GCD來并發(fā)執(zhí)行。

GCD的API很大程度上基于block,當(dāng)然,GCD也可以脫離block來使用,比如使用傳統(tǒng)c機制提供函數(shù)指針和上下文指針。實踐證明,當(dāng)配合block使用時,GCD非常簡單易用且能發(fā)揮其***能力。

你可以在Mac上敲命令“man dispatch”來獲取GCD的文檔。

為何使用?

GCD提供很多超越傳統(tǒng)多線程編程的優(yōu)勢:

  1. 易用: GCD比之thread跟簡單易用。由于GCD基于work unit而非像thread那樣基于運算,所以GCD可以控制諸如等待任務(wù)結(jié)束、監(jiān)視文件描述符、周期執(zhí)行代碼以及工作掛起等任務(wù)?;赽lock的血統(tǒng)導(dǎo)致它能極為簡單得在不同代碼作用域之間傳遞上下文。
  2. 效率: GCD被實現(xiàn)得如此輕量和優(yōu)雅,使得它在很多地方比之專門創(chuàng)建消耗資源的線程更實用且快速。這關(guān)系到易用性:導(dǎo)致GCD易用的原因有一部分在于你可以不用擔(dān)心太多的效率問題而僅僅使用它就行了。
  3. 性能: GCD自動根據(jù)系統(tǒng)負載來增減線程數(shù)量,這就減少了上下文切換以及增加了計算效率。

Dispatch Objects

盡管GCD是純c語言的,但它被組建成面向?qū)ο蟮娘L(fēng)格。GCD對象被稱為dispatch object。Dispatch object像Cocoa對象一樣是引用計數(shù)的。使用dispatch_release和dispatch_retain函數(shù)來操作dispatch object的引用計數(shù)來進行內(nèi)存管理。但主意不像Cocoa對象,dispatch object并不參與垃圾回收系統(tǒng),所以即使開啟了GC,你也必須手動管理GCD對象的內(nèi)存。

Dispatch queues 和 dispatch sources(后面會介紹到)可以被掛起和恢復(fù),可以有一個相關(guān)聯(lián)的任意上下文指針,可以有一個相關(guān)聯(lián)的任務(wù)完成觸發(fā)函數(shù)。可以查閱“man dispatch_object”來獲取這些功能的更多信息。

Dispatch Queues

GCD的基本概念就是dispatch queue。dispatch queue是一個對象,它可以接受任務(wù),并將任務(wù)以先到先執(zhí)行的順序來執(zhí)行。dispatch queue可以是并發(fā)的或串行的。并發(fā)任務(wù)會像NSOperationQueue那樣基于系統(tǒng)負載來合適地并發(fā)進行,串行隊列同一時間只執(zhí)行單一任務(wù)。

GCD中有三種隊列類型:

  1. The main queue: 與主線程功能相同。實際上,提交至main queue的任務(wù)會在主線程中執(zhí)行。main queue可以調(diào)用dispatch_get_main_queue()來獲得。因為main queue是與主線程相關(guān)的,所以這是一個串行隊列。
  2. Global queues: 全局隊列是并發(fā)隊列,并由整個進程共享。進程中存在三個全局隊列:高、中(默認)、低三個優(yōu)先級隊列??梢哉{(diào)用dispatch_get_global_queue函數(shù)傳入優(yōu)先級來訪問隊列。
  3. 用戶隊列: 用戶隊列 (GCD并不這樣稱呼這種隊列, 但是沒有一個特定的名字來形容這種隊列,所以我們稱其為用戶隊列) 是用函數(shù) dispatch_queue_create 創(chuàng)建的隊列. 這些隊列是串行的。正因為如此,它們可以用來完成同步機制, 有點像傳統(tǒng)線程中的mutex。

創(chuàng)建隊列

要使用用戶隊列,我們首先得創(chuàng)建一個。調(diào)用函數(shù)dispatch_queue_create就行了。函數(shù)的***個參數(shù)是一個標(biāo)簽,這純是為了debug。Apple建議我們使用倒置域名來命名隊列,比如“com.dreamingwish.subsystem.task”。這些名字會在崩潰日志中被顯示出來,也可以被調(diào)試器調(diào)用,這在調(diào)試中會很有用。第二個參數(shù)目前還不支持,傳入NULL就行了。

提交 Job

向一個隊列提交Job很簡單:調(diào)用dispatch_async函數(shù),傳入一個隊列和一個block。隊列會在輪到這個block執(zhí)行時執(zhí)行這個block的代碼。下面的例子是一個在后臺執(zhí)行一個巨長的任務(wù):

  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
  2.         [self goDoSomethingLongAndInvolved]; 
  3.         NSLog(@"Done doing something long and involved"); 
  4. }); 

dispatch_async 函數(shù)會立即返回, block會在后臺異步執(zhí)行。 

當(dāng)然,通常,任務(wù)完成時簡單地NSLog個消息不是個事兒。在典型的Cocoa程序中,你很有可能希望在任務(wù)完成時更新界面,這就意味著需要在主線程中執(zhí)行一些代碼。你可以簡單地完成這個任務(wù)——使用嵌套的dispatch,在外層中執(zhí)行后臺任務(wù),在內(nèi)層中將任務(wù)dispatch到main queue:

  1. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
  2.         [self goDoSomethingLongAndInvolved]; 
  3.         dispatch_async(dispatch_get_main_queue(), ^{ 
  4.             [textField setStringValue:@"Done doing something long and involved"]; 
  5.         }); 
  6. }); 

還有一個函數(shù)叫dispatch_sync,它干的事兒和dispatch_async相同,但是它會等待block中的代碼執(zhí)行完成并返回。結(jié)合 __block類型修飾符,可以用來從執(zhí)行中的block獲取一個值。例如,你可能有一段代碼在后臺執(zhí)行,而它需要從界面控制層獲取一個值。那么你可以使用dispatch_sync簡單辦到:

  1. __block NSString *stringValue; 
  2. dispatch_sync(dispatch_get_main_queue(), ^{ 
  3.         // __block variables aren't automatically retained 
  4.         // so we'd better make sure we have a reference we can keep 
  5.         stringValue = [[textField stringValue] copy]; 
  6. }); 
  7. [stringValue autorelease]; 
  8. // use stringValue in the background now 

我們還可以使用更好的方法來完成這件事——使用更“異步”的風(fēng)格。不同于取界面層的值時要阻塞后臺線程,你可以使用嵌套的block來中止后臺線程,然后從主線程中獲取值,然后再將后期處理提交至后臺線程:

  1. dispatch_queue_t bgQueue = myQueue; 
  2.    dispatch_async(dispatch_get_main_queue(), ^{ 
  3.        NSString *stringValue = [[[textField stringValue] copy] autorelease]; 
  4.        dispatch_async(bgQueue, ^{ 
  5.            // use stringValue in the background now 
  6.        }); 
  7.    }); 

取決于你的需求,myQueue可以是用戶隊列也可以使全局隊列。

不再使用鎖(Lock)

用戶隊列可以用于替代鎖來完成同步機制。在傳統(tǒng)多線程編程中,你可能有一個對象要被多個線程使用,你需要一個鎖來保護這個對象:

  1. NSLock *lock; 

訪問代碼會像這樣:

  1. - (id)something 
  2.    { 
  3.        id localSomething; 
  4.        [lock lock]; 
  5.        localSomething = [[something retain] autorelease]; 
  6.        [lock unlock]; 
  7.        return localSomething; 
  8.    } 
  9.  
  10.    - (void)setSomething:(id)newSomething 
  11.    { 
  12.        [lock lock]; 
  13.        if(newSomething != something) 
  14.        { 
  15.            [something release]; 
  16.            something = [newSomething retain]; 
  17.            [self updateSomethingCaches]; 
  18.        } 
  19.        [lock unlock]; 
  20.    } 

使用GCD,可以使用queue來替代:

  1. dispatch_queue_t queue; 

要用于同步機制,queue必須是一個用戶隊列,而非全局隊列,所以使用usingdispatch_queue_create初始化一個。然后可以用dispatch_async 或者 dispatch_sync將共享數(shù)據(jù)的訪問代碼封裝起來:

  1. - (id)something 
  2.     __block id localSomething; 
  3.     dispatch_sync(queue, ^{ 
  4.         localSomething = [something retain]; 
  5.     }); 
  6.     return [localSomething autorelease]; 
  7.  
  8. - (void)setSomething:(id)newSomething 
  9.     dispatch_async(queue, ^{ 
  10.         if(newSomething != something) 
  11.         { 
  12.             [something release]; 
  13.             something = [newSomething retain]; 
  14.             [self updateSomethingCaches]; 
  15.         } 
  16.     }); 

值得注意的是dispatch queue是非常輕量級的,所以你可以大用特用,就像你以前使用lock一樣。

現(xiàn)在你可能要問:“這樣很好,但是有意思嗎?我就是換了點代碼辦到了同一件事兒。”

實際上,使用GCD途徑有幾個好處:

  1. 平行計算: 注意在第二個版本的代碼中, -setSomething:是怎么使用dispatch_async的。調(diào)用 -setSomething:會立即返回,然后這一大堆工作會在后臺執(zhí)行。如果updateSomethingCaches是一個很費時費力的任務(wù),且調(diào)用者將要進行一項處理器高負荷任務(wù),那么這樣做會很棒。
  2. 安全: 使用GCD,我們就不可能意外寫出具有不成對Lock的代碼。在常規(guī)Lock代碼中,我們很可能在解鎖之前讓代碼返回了。使用GCD,隊列通常持續(xù)運行,你必將歸還控制權(quán)。
  3. 控制: 使用GCD我們可以掛起和恢復(fù)dispatch queue,而這是基于鎖的方法所不能實現(xiàn)的。我們還可以將一個用戶隊列指向另一個dspatch queue,使得這個用戶隊列繼承那個dispatch queue的屬性。使用這種方法,隊列的優(yōu)先級可以被調(diào)整——通過將該隊列指向一個不同的全局隊列,若有必要的話,這個隊列甚至可以被用來在主線程上執(zhí)行代碼。
  4. 集成: GCD的事件系統(tǒng)與dispatch queue相集成。對象需要使用的任何事件或者計時器都可以從該對象的隊列中指向,使得這些句柄可以自動在該隊列上執(zhí)行,從而使得句柄可以與對象自動同步。

總結(jié)

現(xiàn)在你已經(jīng)知道了GCD的基本概念、怎樣創(chuàng)建dispatch queue、怎樣提交Job至dispatch queue以及怎樣將隊列用作線程同步。接下來我會向你展示如何使用GCD來編寫平行執(zhí)行代碼來充分利用多核系統(tǒng)的性能^ ^。我還會討論GCD更深層的東西,包括事件系統(tǒng)和queue targeting。

責(zé)任編輯:閆佳明 來源: dreamingwish
相關(guān)推薦

2013-07-15 16:18:08

2010-03-09 13:36:41

Linux基本概念

2009-08-18 10:34:31

Java入門基本概念

2009-12-21 10:27:52

WCF基本概念

2010-06-12 14:12:22

RSVP協(xié)議

2010-06-29 13:00:49

EIGRP協(xié)議

2010-08-16 16:23:00

Eclipse插件

2010-04-22 12:27:16

Aix操作系統(tǒng)

2010-03-16 14:13:20

無線Mesh網(wǎng)絡(luò)

2011-08-22 15:19:25

2011-03-28 11:05:17

ODBC

2013-04-16 10:45:52

Android基本概念

2014-04-16 15:11:19

Spark

2012-09-11 14:39:03

Moosefs

2009-03-20 11:46:10

MGCP協(xié)議網(wǎng)關(guān)

2023-06-14 00:21:52

2010-04-19 10:08:46

Oracle視圖

2017-05-02 14:45:11

深度學(xué)習(xí)機器學(xué)習(xí)人工神經(jīng)網(wǎng)絡(luò)

2010-06-08 16:11:10

SPI總線協(xié)議

2011-07-19 13:44:39

JavaScript
點贊
收藏

51CTO技術(shù)棧公眾號