3阵难、GCD-Objc - Part 2

GCD 文檔的查看
GCD 最全的資料不在百度鞋喇,不在 api ,在 mac 終端卧蜓。
打開終端

$ man dispatch
Snip20160623_4.png
// 退出當(dāng)前界面
$ q 

see also
我們可以通過輸入 man dispatch_after 查看相應(yīng)的文檔帐要。

// dispatch_after 函數(shù)的文檔
$ man dispatch_after

// dispatch_async 函數(shù)的文檔
$ man dispatch_async

1、隊列同步任務(wù)和異步任務(wù)在項目中的使用

假設(shè): a 為登錄弥奸, b宠叼, c 為不同的下載任務(wù)。
下面這樣的操作就可以保證其爵,只有在登錄的情況下才可以進(jìn)行 下載任務(wù)冒冬。

// 創(chuàng)建一個并發(fā)隊列
dispatch_queue_t q = dispatch_queue_create("demo", DISPATCH_QUEUE_CONCURRENT);


// 并發(fā)隊列同步執(zhí)行
// 不會開線程,會在當(dāng)前線程執(zhí)行
// 同步執(zhí)行任務(wù) - 作用可以讓一些異步執(zhí)行的任務(wù)"依賴" 某一個特殊的任務(wù)
dispatch_sync(q, ^{
    NSLog(@"a: %@",[NSThread currentThread]);
});


// 永遠(yuǎn)都是在 a 執(zhí)行完畢后摩渺,在回執(zhí)行 b c 简烤,但是 b ,  c 執(zhí)行的順序是不定的。


// 并發(fā)隊列異步執(zhí)行
// 會開線程摇幻,在子線程運(yùn)行
dispatch_async(q, ^{
    NSLog(@"b: %@",[NSThread currentThread]);
});


dispatch_async(q, ^{
    NSLog(@"c: %@",[NSThread currentThread]);
});

打印結(jié)果:
2016-06-21 12:22:01.900 Thread-Objc[44983:2486117] a: <NSThread: 0x7f8762501ba0>{number = 1, name = main}
2016-06-21 12:22:01.900 Thread-Objc[44983:2486394] c: <NSThread: 0x7f876257ac90>{number = 3, name = (null)}
2016-06-21 12:22:01.900 Thread-Objc[44983:2486385] b: <NSThread: 0x7f8762717f20>{number = 2, name = (null)}

2横侦、隊列迭代

提交一個任務(wù)到隊列進(jìn)行多次執(zhí)行

/*
  size_t iterations :         任務(wù)執(zhí)行的次數(shù)
  dispatch_queue_t queue :   要執(zhí)行任務(wù)的隊列
  void (^block)(size_t) :    要執(zhí)行的任務(wù)
*/
void
dispatch_apply(size_t iterations, dispatch_queue_t queue,
        void (^block)(size_t));


// 上面函數(shù)是下面的封裝。
void
dispatch_apply_f(size_t iterations, dispatch_queue_t queue,
    void *context,
    void (*work)(void *, size_t));

如果 dispatch_queue_t queue 的隊列是并發(fā)隊列绰姻。任務(wù)是并發(fā)執(zhí)行的, 它必須是可重入的安全枉侧。

dispatch_apply( ) 是同步執(zhí)行的。 意味著會阻塞當(dāng)前線程狂芋。和 for 循環(huán)一樣只有在迭代完成后才會返回榨馁。如果需要異步執(zhí)行,就需要創(chuàng)建一個新的 隊列帜矾,調(diào)用 dispatch_async() 函數(shù)翼虫,再在 dispatch_async() 函數(shù)中調(diào)用 dispatch_apply( )。
示例:

 NSLog(@"before: %@", [NSThread currentThread]);
    
 __block int x = 0;

  // q 是串行或者并行沒有多大的關(guān)系
 dispatch_queue_t q = dispatch_queue_create("q", DISPATCH_QUEUE_CONCURRENT);
    
 dispatch_async(q, ^{

        // q1 是串行的屡萤,就只開1條線程珍剑,并發(fā)的就開多條線程。線程數(shù)由 GCD 決定死陆。
        dispatch_queue_t q1 = dispatch_queue_create("q1", DISPATCH_QUEUE_SERIAL);
        size_t iterations = 10;
        dispatch_apply( iterations, q1, ^(size_t idx ) {
            NSLog(@"size_t : %zd --- x : %zd -- %@", idx, x, [NSThread currentThread]);
        });
});
NSLog(@"after: %@", [NSThread currentThread]);

在主線程中調(diào)用 dispatch_apply( ) 傳入的是主隊列招拙,會造成死鎖。

文檔中說:
dispatch_apply() 是 dispatch_async() 和 semaphore (完成信號)的包裝;

(我特么真沒看出來)
dispatch_apply() 和 dispatch_async() 不一樣的地方是别凤,block 提交到 dispatch_apply() 是相對獨(dú)立的劈愚,或者是依賴于已經(jīng)完成但是 index 比自己小的 block 。

這個函數(shù)就像 for 循環(huán)一樣提供數(shù)據(jù)級并發(fā)闻妓。 相對于 for 循環(huán)(for 循序操作都是在當(dāng)前線程),并發(fā)迭代 的效率更加的高掠械。

使用前提條件:
本次的迭代執(zhí)行的 block 和上一次迭代執(zhí)行的 block 不能有任何的關(guān)系由缆。
(每次 block 的迭代執(zhí)行是相對獨(dú)立的!猾蒂。 如果說執(zhí)行的 block 之間有依賴關(guān)系均唉,那你還是放棄吧!)

如果你使用循環(huán)執(zhí)行固定次數(shù)的迭代, 并發(fā)dispatch queue可能會提高性能肚菠。

  • 如果每次迭代執(zhí)行的任務(wù)與其它迭代獨(dú)立無關(guān),而且循環(huán)迭代執(zhí)行順序也無關(guān)緊要的話,你可以調(diào)用dispatch_apply或dispatch_apply_f函數(shù)來替換循環(huán)舔箭。

普通 for 循環(huán)

NSLog(@"before: %@", [NSThread currentThread]);
int x = 0;
for (int index = 0 ; index < 10; index ++) {
        NSLog(@"task: %@  --- index : %zd  ---- x : %zd", [NSThread currentThread], index , x );
        x++;
}
    
NSLog(@"after: %@", [NSThread currentThread]);

打印結(jié)果:
2016-06-23 14:55:04.706 Thread-Objc[12389:1352331] before: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}
2016-06-23 14:55:04.707 Thread-Objc[12389:1352331] task: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}  --- index : 0  ---- x : 0
2016-06-23 14:55:04.707 Thread-Objc[12389:1352369] task: <NSThread: 0x7f97f2626000>{number = 2, name = (null)}  --- index : 1  ---- x : 0
2016-06-23 14:55:04.707 Thread-Objc[12389:1352381] task: <NSThread: 0x7f97f2635530>{number = 3, name = (null)}  --- index : 2  ---- x : 0
2016-06-23 14:55:04.707 Thread-Objc[12389:1352375] task: <NSThread: 0x7f97f2635970>{number = 4, name = (null)}  --- index : 3  ---- x : 0
2016-06-23 14:55:04.708 Thread-Objc[12389:1352331] task: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}  --- index : 4  ---- x : 1
2016-06-23 14:55:04.708 Thread-Objc[12389:1352369] task: <NSThread: 0x7f97f2626000>{number = 2, name = (null)}  --- index : 5  ---- x : 2
2016-06-23 14:55:04.708 Thread-Objc[12389:1352381] task: <NSThread: 0x7f97f2635530>{number = 3, name = (null)}  --- index : 6  ---- x : 3
2016-06-23 14:55:04.709 Thread-Objc[12389:1352375] task: <NSThread: 0x7f97f2635970>{number = 4, name = (null)}  --- index : 7  ---- x : 4
2016-06-23 14:55:04.709 Thread-Objc[12389:1352331] task: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}  --- index : 8  ---- x : 5
2016-06-23 14:55:04.710 Thread-Objc[12389:1352369] task: <NSThread: 0x7f97f2626000>{number = 2, name = (null)}  --- index : 9  ---- x : 6
2016-06-23 14:55:04.721 Thread-Objc[12389:1352331] after: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}

GCD 迭代

NSLog(@"before: %@", [NSThread currentThread]);

size_t iterations = 10;
__block int x = 0;
dispatch_apply( iterations , dispatch_get_global_queue(0, 0), ^(size_t  idx) {
    NSLog(@"task: %@  --- index : %zd  ---- x : %zd", [NSThread currentThread], idx , x );
    x++;
});

NSLog(@"after: %@", [NSThread currentThread]);

打印結(jié)果
2016-06-23 14:55:04.706 Thread-Objc[12389:1352331] before: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}
2016-06-23 14:55:04.707 Thread-Objc[12389:1352331] task: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}  --- index : 0  ---- x : 0
2016-06-23 14:55:04.707 Thread-Objc[12389:1352369] task: <NSThread: 0x7f97f2626000>{number = 2, name = (null)}  --- index : 1  ---- x : 0
2016-06-23 14:55:04.707 Thread-Objc[12389:1352381] task: <NSThread: 0x7f97f2635530>{number = 3, name = (null)}  --- index : 2  ---- x : 0
2016-06-23 14:55:04.707 Thread-Objc[12389:1352375] task: <NSThread: 0x7f97f2635970>{number = 4, name = (null)}  --- index : 3  ---- x : 0
2016-06-23 14:55:04.708 Thread-Objc[12389:1352331] task: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}  --- index : 4  ---- x : 1
2016-06-23 14:55:04.708 Thread-Objc[12389:1352369] task: <NSThread: 0x7f97f2626000>{number = 2, name = (null)}  --- index : 5  ---- x : 2
2016-06-23 14:55:04.708 Thread-Objc[12389:1352381] task: <NSThread: 0x7f97f2635530>{number = 3, name = (null)}  --- index : 6  ---- x : 3
2016-06-23 14:55:04.709 Thread-Objc[12389:1352375] task: <NSThread: 0x7f97f2635970>{number = 4, name = (null)}  --- index : 7  ---- x : 4
2016-06-23 14:55:04.709 Thread-Objc[12389:1352331] task: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}  --- index : 8  ---- x : 5
2016-06-23 14:55:04.710 Thread-Objc[12389:1352369] task: <NSThread: 0x7f97f2626000>{number = 2, name = (null)}  --- index : 9  ---- x : 6
2016-06-23 14:55:04.721 Thread-Objc[12389:1352331] after: <NSThread: 0x7f97f2402dd0>{number = 1, name = main}

對比發(fā)現(xiàn) x 的值在 GCD 迭代的過程中是凌亂的。
當(dāng)符合前提條件蚊逢,GCD 的迭代的效率更高层扶。

3、隊列的暫停和啟動操作

給目標(biāo)隊列添加管理對象

/*
  dispatch_object_t object : 隊列管理對象
  dispatch_queue_t queue : 被管理的隊列

*/
void
dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue);

調(diào)度對象的相關(guān)知識
調(diào)度對象是通過共享函數(shù)去協(xié)調(diào)內(nèi)存管理烙荷,暫停镜会,取消,上下文指針终抽。

  • 掛起操作
    在調(diào)度隊列或者調(diào)度源被觸發(fā)的 blocks 能夠通過分別執(zhí)行 dispatch_suspend()dispatch_resume() 函數(shù)進(jìn)行掛起和啟動操作戳表。另一些調(diào)度對象是不支持掛起操作的。
    這個調(diào)度框架總是在執(zhí)行 block 之前檢查 block 的懸掛狀態(tài)昼伴。一個 block 在執(zhí)行期間對 block 做的改變是不會產(chǎn)生效果的匾旭。因此一個對象的掛起操作是異步的,除非它是通過執(zhí)行上下文從目標(biāo)隊列獲取的對象圃郊。把一個不是調(diào)度隊列或調(diào)度源的對象執(zhí)行掛起操作或啟用操作的操作結(jié)果是沒有定義的价涝。

重點(diǎn):
懸掛操作適用于調(diào)度對象生命周期的任何時候。包括 finalizer 函數(shù)持舆,取消回調(diào)飒泻。 掛起操作會使計數(shù)器加1 ,啟用操作會使計數(shù)器減一吏廉。因此泞遗, dispatch_suspend()dispatch_resume()進(jìn)行成對調(diào)用,以保證對象最終能夠釋放席覆。一個調(diào)度對象在所有的引用釋放后進(jìn)行掛起操作的操作結(jié)果是沒有定義的史辙。

  • 上下文指針
    調(diào)度對象支持補(bǔ)充(追加)上下文指針。 上下文指針的值能夠分別通過 dispatch_get_context()dispatch_set_context() 函數(shù)進(jìn)行獲取和更新。 當(dāng)調(diào)度對象所有的引用全部釋放的時候聊倔,如果上下文指針是非空的晦毙,通過dispatch_set_finalizer_f() 能給每一個可選的對象指定一個可以異步調(diào)用的終結(jié)函數(shù)。給應(yīng)用程序一個可以給調(diào)度自由關(guān)聯(lián)上下文數(shù)據(jù)的機(jī)會耙蔑。這個終結(jié)器將要運(yùn)行在和 調(diào)度對象綁定的目標(biāo)隊列上见妒。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市甸陌,隨后出現(xiàn)的幾起案子须揣,更是在濱河造成了極大的恐慌,老刑警劉巖钱豁,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件耻卡,死亡現(xiàn)場離奇詭異,居然都是意外死亡牲尺,警方通過查閱死者的電腦和手機(jī)卵酪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谤碳,“玉大人溃卡,你說我怎么就攤上這事⊙鸭颍” “怎么了塑煎?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長臭蚁。 經(jīng)常有香客問我最铁,道長,這世上最難降的妖魔是什么垮兑? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任冷尉,我火速辦了婚禮,結(jié)果婚禮上系枪,老公的妹妹穿的比我還像新娘雀哨。我一直安慰自己,他們只是感情好私爷,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布雾棺。 她就那樣靜靜地躺著,像睡著了一般衬浑。 火紅的嫁衣襯著肌膚如雪捌浩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天工秩,我揣著相機(jī)與錄音尸饺,去河邊找鬼进统。 笑死,一個胖子當(dāng)著我的面吹牛浪听,可吹牛的內(nèi)容都是我干的螟碎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼迹栓,長吁一口氣:“原來是場噩夢啊……” “哼掉分!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起克伊,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤酥郭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后答毫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡季春,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年洗搂,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片载弄。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡耘拇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宇攻,到底是詐尸還是另有隱情惫叛,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布逞刷,位于F島的核電站嘉涌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏夸浅。R本人自食惡果不足惜仑最,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望帆喇。 院中可真熱鬧警医,春花似錦、人聲如沸坯钦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽婉刀。三九已至吟温,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間突颊,已是汗流浹背溯街。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工诱桂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呈昔。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓挥等,卻偏偏與公主長得像,于是被迫代替她去往敵國和親堤尾。 傳聞我的和親對象是個殘疾皇子肝劲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容

  • GCD調(diào)度隊列是執(zhí)行任務(wù)的強(qiáng)大工具。調(diào)度隊列允許您相對于調(diào)度者異步或者同步的執(zhí)行任意代碼塊郭宝。您能夠使用調(diào)度隊列來執(zhí)...
    坤坤同學(xué)閱讀 6,673評論 1 3
  • GCD筆記 總結(jié)一下多線程部分,最強(qiáng)大的無疑是GCD,那么先從這一塊部分講起. Dispatch Queue的種類...
    jins_1990閱讀 761評論 0 1
  • GCD (Grand Central Dispatch) :iOS4 開始引入辞槐,使用更加方便,程序員只需要將任務(wù)添...
    池鵬程閱讀 1,332評論 0 2
  • 一鹿榜、多線程簡介: 所謂多線程是指一個 進(jìn)程 -- process(可以理解為系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序)中可以開...
    尋形覓影閱讀 1,030評論 0 6
  • iOS 多線程系列 -- 基礎(chǔ)概述iOS 多線程系列 -- pthreadiOS 多線程系列 -- NSThrea...
    shannoon閱讀 849評論 0 2