GCD回顧系列之Queues
GCD Objects
當(dāng)你使用Objective-C編譯器構(gòu)建你的App,所有的dispatch object是Obejctive-C對(duì)象醇锚。
引用Queue基本對(duì)象為dispatch_queue_t;在MRC下侄旬,使用*dispatch_retain 和 dispatch_release函數(shù)來(lái)retain 和release你的dispatch objects,而不是使用Core Foundatons函數(shù)钻注。如果你想在ARC下篮撑,使用retain/release語(yǔ)義逞壁,需要添加 DOS_OBJECT_USE_OBJC=0編譯標(biāo)記位猎莲,參考位置.
GCD QueueTasks
Queues 分類
GCD在應(yīng)用中管理FIFO queues,以block對(duì)象的形式提交任務(wù)到隊(duì)列中,最終有系統(tǒng)線程池來(lái)執(zhí)行绍弟。GCD提供了是哪種類型的隊(duì)列:
+Main: 在應(yīng)用主隊(duì)列中任務(wù)串行執(zhí)行。
+Concurrent: 以FIFO順序入隊(duì)著洼,但是并發(fā)執(zhí)行樟遣,隊(duì)列任務(wù)完成順序?yàn)闊o(wú)序而叼。
+Serial: 以FIFO順序一次只執(zhí)行一個(gè)。
Note
并發(fā)和并行從宏觀上來(lái)講都是同時(shí)處理多路請(qǐng)求的概念豹悬。但并發(fā)和并行又有區(qū)別葵陵,并行是指兩個(gè)或者多個(gè)事件在同一時(shí)刻發(fā)生;而并發(fā)是指兩個(gè)或多個(gè)事件在同一時(shí)間間隔內(nèi)發(fā)生屿衅。
Queues創(chuàng)建方式
主隊(duì)列
主隊(duì)列被系統(tǒng)自動(dòng)創(chuàng)建埃难,與應(yīng)用程序的主線程關(guān)聯(lián),屬于串行隊(duì)列。應(yīng)用程序使用以下三種形式調(diào)用提交到主隊(duì)列的block:
- dispatch_main
- UIApplicationMain(iOS)
- 在主隊(duì)列中使用 CFRunLoopRef
獲取主隊(duì)列的方式:dispatch_get_main_queue()
串行隊(duì)列Serial
<pre> dispatch_queue_t serialQueue = dispatch_queue_create("com.allan.queue", DISPATCH_QUEUE_SERIAL); //DISPATCH_QUEUE_SERIAL也可寫(xiě)為NULL
</pre>
并發(fā)隊(duì)列Concurrent
1.全局方式
<pre> dispatch_queue_t gloalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);全局共享并發(fā)隊(duì)列
//第一個(gè)參數(shù):優(yōu)先升級(jí) 第二個(gè)參數(shù):預(yù)留標(biāo)記為涤久,一般設(shè)置為0</pre>
優(yōu)先級(jí)分類為:
define DISPATCH_QUEUE_PRIORITY_HIGH 2
define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
define DISPATCH_QUEUE_PRIORITY_LOW (-2)
define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
iOS8新加了一個(gè)功能叫Quality of Service(QoS)涡尘,里面提供了一下幾個(gè)更容易理解的枚舉名來(lái)使用user interactive,user initiated响迂,utility和background,以下為對(duì)應(yīng)表
<pre>
- DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED
- DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT
- DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY
- DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND
</pre>
詳細(xì)描述
5種隊(duì)列考抄,主隊(duì)列(main queue),四種通用調(diào)度隊(duì)列,自己定制的隊(duì)列蔗彤。四種通用調(diào)度隊(duì)列為
- DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND
QOS_CLASS_USER_INTERACTIVE:user interactive等級(jí)表示任務(wù)需要被立即執(zhí)行提供好的體驗(yàn)川梅,用來(lái)更新UI,響應(yīng)事件等然遏。這個(gè)等級(jí)最好保持小規(guī)模贫途。
QOS_CLASS_USER_INITIATED:user initiated等級(jí)表示任務(wù)由UI發(fā)起異步執(zhí)行。適用場(chǎng)景是需要及時(shí)結(jié)果同時(shí)又可以繼續(xù)交互的時(shí)候待侵。
QOS_CLASS_UTILITY:utility等級(jí)表示需要長(zhǎng)時(shí)間運(yùn)行的任務(wù)丢早,伴有用戶可見(jiàn)進(jìn)度指示器。經(jīng)常會(huì)用來(lái)做計(jì)算秧倾,I/O怨酝,網(wǎng)絡(luò),持續(xù)的數(shù)據(jù)填充等任務(wù)那先。這個(gè)任務(wù)節(jié)能
QOS_CLASS_BACKGROUND:background等級(jí)表示用戶不會(huì)察覺(jué)的任務(wù)农猬,使用它來(lái)處理預(yù)加載,或者不需要用戶交互和對(duì)時(shí)間不敏感的任務(wù).
參考:Building Responsive and Efficient Apps with GCD
2.自定義方式
<pre>dispatch_queue_t concurrentQueue = dispatch_queue_create("com.allan.concurrent", DISPATCH_QUEUE_CONCURRENT);
</pre>
小插曲
1.獲取自定義隊(duì)列的名字
<pre>dispatch_queue_get_label(concurrentQueue)</pre>
Queues執(zhí)行方式
1.同步執(zhí)行
dispatch_sync(yourQueue, ^{});
應(yīng)用
同步鎖售淡,隊(duì)列類型為自定義串行隊(duì)列斤葱。
2.異步執(zhí)行
dispatch_async(yourQueue, ^{});
3.延遲執(zhí)行
<pre>
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 33ull * NSEC_PER_SEC);
dispatch_after(time, concurrentQueue, ^{
});</pre>
4.快速迭代執(zhí)行
<pre>
dispatch_apply(5, concurrentQueue, ^(size_t location) {
NSLog(@"執(zhí)行-%d",location);
});
//第一個(gè)參數(shù):執(zhí)行次數(shù), 第二個(gè)參數(shù):隊(duì)列類型
</pre>
調(diào)節(jié)Queues優(yōu)先級(jí)
1.dipatch_queue_attr_make_with_qos_class
<pre>
dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, 100);
dispatch_queue_t queue = dispatch_queue_create("com.allan.qosqueue", attr);
</pre>
2.dispatch_set_target_queue
dispatch_set_target_queue(queue1, targetQueue);這樣設(shè)置時(shí)揖闸,相當(dāng)于將queue1指派給targetQueue苦掘,如果targetQueue是串行隊(duì)列,則queue1是串行執(zhí)行的楔壤;如果targetQueue是并行隊(duì)列,那么queue1是并行的惯驼。
2.1設(shè)置優(yōu)先級(jí)
<pre>
dispatch_queue_t queue = dispatch_queue_create("com.allan.settargetqueue",); //需要設(shè)置優(yōu)先級(jí)的queue
dispatch_queue_t referQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, ); //參考優(yōu)先級(jí)
dispatch_set_target_queue(queue, referQueue); //設(shè)置queue和referQueue的優(yōu)先級(jí)一樣
</pre>
2.2設(shè)置隊(duì)列層級(jí)體系
將一個(gè)用戶隊(duì)列的目標(biāo)隊(duì)列指定為另一個(gè)用戶隊(duì)列蹲嚣。這樣做可以強(qiáng)制多個(gè)隊(duì)列相互協(xié)調(diào)地串行執(zhí)行递瑰,這樣足以構(gòu)建一組隊(duì)列,通過(guò)掛起和暫停那個(gè)目標(biāo)隊(duì)列隙畜,我們可以掛起和暫停整個(gè)組
<pre>
dispatch_queue_t serialQueue = dispatch_queue_create("com.allan.serialqueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t firstQueue = dispatch_queue_create("com.allan.firstqueue", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t secondQueue = dispatch_queue_create("com.allan.secondqueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_set_target_queue(firstQueue, serialQueue);
dispatch_set_target_queue(secondQueue, serialQueue);
dispatch_async(firstQueue, ^{
NSLog(@"1");
});
dispatch_async(secondQueue, ^{
NSLog(@"2");
});
dispatch_async(secondQueue, ^{
NSLog(@"3");
});
</pre>
Queues掛起
dispatch queue可以被掛起和恢復(fù)抖部。使用 dispatch_suspend函數(shù)來(lái)掛起,使用 dispatch_resume 函數(shù)來(lái)恢復(fù)议惰。這兩個(gè)函數(shù)的行為是如你所愿的慎颗。另外,這兩個(gè)函數(shù)也可以用于dispatch source言询。
一個(gè)要注意的地方是俯萎,dispatch queue的掛起是block粒度的。換句話說(shuō)运杭,掛起一個(gè)queue并不會(huì)將當(dāng)前正在執(zhí)行的block掛起夫啊。它會(huì)允許當(dāng)前執(zhí)行的block執(zhí)行完畢,然后后續(xù)的block不再會(huì)被執(zhí)行辆憔,直至queue被恢復(fù)撇眯。
還有一個(gè)注意點(diǎn):從main上得來(lái)的:如果你掛起了一個(gè)queue或者source,那么銷毀它之前虱咧,必須先對(duì)其進(jìn)行恢復(fù)熊榛。
參考文章
1https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/doc/uid/TP40008079-CH2-SW66
2.http://www.reibang.com/p/fbe6a654604c