国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計(jì) > 正文

iOS多線程實(shí)現(xiàn)3-GCD

2019-11-14 18:26:24
字體:
供稿:網(wǎng)友

原文鏈接:http://www.survivalescaperooms.com/mddblog/p/4767559.html  

  敲下gcd三個(gè)字母,搜狗第一條顯示居然是“滾床單” ^_^

一、介紹

  GCD,英文全稱是Grand Central Dispatch(功能強(qiáng)悍的中央調(diào)度器),基于C語言編寫的一套多線程開發(fā)機(jī)制,因此使用時(shí)會(huì)以函數(shù)形式出現(xiàn),且大部分函數(shù)以dispatch開頭,雖然是C語言的但相對(duì)于蘋果其它多線程實(shí)現(xiàn)方式,抽象層次更高,使用起來也更加方便。

  它是蘋果為應(yīng)對(duì)多核的并行運(yùn)算提出的解決方案,它會(huì)自動(dòng)利用多核進(jìn)行并發(fā)處理和運(yùn)算,且線程由系統(tǒng)自動(dòng)管理(調(diào)度、運(yùn)行),無需程序員參與,使用起來非常方便。

二、任務(wù)和隊(duì)列

  GCD有兩個(gè)核心:任務(wù)和隊(duì)列。

  任務(wù):要執(zhí)行的操作或方法函數(shù),隊(duì)列:存放任務(wù)的集合,而我們要做的就是將任務(wù)添加到隊(duì)列然后執(zhí)行,GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)按先進(jìn)先出的方式取出并交給對(duì)應(yīng)線程執(zhí)行。注意任務(wù)的取出是按照先進(jìn)先出的方式,這也是隊(duì)列的特性,但是取出后的執(zhí)行順序則不一定,下面會(huì)詳細(xì)討論。

  1 任務(wù)

  可以簡單的認(rèn)為是一個(gè)操作,一個(gè)函數(shù),一個(gè)方法等等,在實(shí)際的開發(fā)中大多是以block(block使用詳見)的形式,使用起來也更加靈活。

  2 隊(duì)列

  有兩種隊(duì)列:串行隊(duì)列和并行隊(duì)列。串行隊(duì)列:同步執(zhí)行,在當(dāng)前線程執(zhí)行;并行隊(duì)列:可由多個(gè)線程異步執(zhí)行,但任務(wù)的取出還是FIFO的。

    隊(duì)列創(chuàng)建,根據(jù)函數(shù)第二個(gè)參數(shù)來創(chuàng)建串行或并行隊(duì)列。

// 參數(shù)1 隊(duì)列名稱// 參數(shù)2 隊(duì)列類型 DISPATCH_QUEUE_SERIAL/NULL串行隊(duì)列,DISPATCH_QUEUE_CONCURRENT代表并行隊(duì)列// 下面代碼為創(chuàng)建一個(gè)串行隊(duì)列,也是實(shí)際開發(fā)中用的最多的dispatch_queue_t serialQ = dispatch_queue_create("隊(duì)列名", NULL);

  另外系統(tǒng)提供了兩種隊(duì)列:全局隊(duì)列和主隊(duì)列。

    全局隊(duì)列屬于并行隊(duì)列,只不過已由系統(tǒng)創(chuàng)建的沒有名字,且在全局可見(可用)。獲取全局隊(duì)列:

/* 取得全局隊(duì)列 第一個(gè)參數(shù):線程優(yōu)先級(jí),設(shè)為默認(rèn)即可,個(gè)人習(xí)慣寫0,等同于默認(rèn) 第二個(gè)參數(shù):標(biāo)記參數(shù),目前沒有用,一般傳入0 */serialQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    主隊(duì)列屬于串行隊(duì)列,也由系統(tǒng)創(chuàng)建,只不過運(yùn)行在主線程(UI線程)。獲取主隊(duì)列:

// 獲取主隊(duì)列serialQ = dispatch_get_main_queue();

  3 執(zhí)行方式-2種

  同步執(zhí)行和異步執(zhí)行。

    同步執(zhí)行:不會(huì)開啟線程,在當(dāng)前線程執(zhí)行。

    異步執(zhí)行:gcd管理的線程池中有空閑線程就會(huì)從隊(duì)列中取出任務(wù)執(zhí)行,會(huì)開啟線程。

  下面為實(shí)現(xiàn)同步和異步的函數(shù),函數(shù)功能為:將任務(wù)添加到隊(duì)列并執(zhí)行。

/* 同步執(zhí)行 第一個(gè)參數(shù):執(zhí)行任務(wù)的隊(duì)列:串行、并行、全局、主隊(duì)列 第二個(gè)參數(shù):block任務(wù) */void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);// 異步執(zhí)行void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

三、幾種類型

  很明顯兩種執(zhí)行方式,兩種隊(duì)列。那么就有4種情況:串行隊(duì)列同步執(zhí)行、串行隊(duì)列異步執(zhí)行、并行隊(duì)列同步執(zhí)行、并行隊(duì)列異步執(zhí)行。哪一種會(huì)開啟新的線程?開幾條?是否并發(fā)?記憶起來比較繞,但是只要抓住基本的就可以,為了方便理解,現(xiàn)分析如下:

  1)串行隊(duì)列,同步執(zhí)行-----串行隊(duì)列意味著順序執(zhí)行,同步執(zhí)行意味著不開啟線程(在當(dāng)前線程執(zhí)行)

  2)串行隊(duì)列,異步執(zhí)行-----串行隊(duì)列意味著任務(wù)順序執(zhí)行,異步執(zhí)行說明要開線程, (如果開多個(gè)線程的話,不能保證串行隊(duì)列順序執(zhí)行,所以只開一個(gè)線程)

  3)并行隊(duì)列,異步執(zhí)行-----并行隊(duì)列意味著執(zhí)行順序不確定,異步執(zhí)行意味著會(huì)開啟線程,而并行隊(duì)列又允許不按順序執(zhí)行,所以系統(tǒng)為了提高性能會(huì)開啟多個(gè)線程,來隊(duì)列取任務(wù)(隊(duì)列中任務(wù)取出仍然是順序取出的,只是線程執(zhí)行無序)。

  4)并行隊(duì)列,同步執(zhí)行-----同步執(zhí)行意味著不開線程,則肯定是順序執(zhí)行

  5)主線程中主隊(duì)列,同步執(zhí)行-----程序執(zhí)行不出來(死鎖) ;原因:主隊(duì)列,如果主線程正在執(zhí)行代碼,就不調(diào)度任務(wù);同步執(zhí)行:一直執(zhí)行第一個(gè)任務(wù)直到結(jié)束。兩者互相等待造成死鎖。

// 在主線程執(zhí)行下面代碼,會(huì)死鎖dispatch_sync(dispatch_get_main_queue(), ^{    // 要執(zhí)行的代碼});

四、常用舉例

  1 線程間通訊

  比如,為了提高用戶體驗(yàn),我們一般在其他線程(非主線程)下載圖片或其它網(wǎng)絡(luò)資源,下載完成后我們要更新UI,而UI更新必須在主線程執(zhí)行,所以我們經(jīng)常會(huì)使用:

// 同步執(zhí)行,會(huì)阻塞指導(dǎo)下面block中的代碼執(zhí)行完畢dispatch_sync(dispatch_get_main_queue(), ^{    // 主線程,UI更新});// 異步執(zhí)行dispatch_async(dispatch_get_main_queue(), ^{    // 主線程,UI更新});

  2 其它常用

  全局隊(duì)列,實(shí)現(xiàn)并發(fā):

dispatch_async(dispatch_get_global_queue(0, 0), ^{    // 要執(zhí)行的代碼});

五、Dispatch Group調(diào)度組

  使用調(diào)度組,可以輕松實(shí)現(xiàn)在一些任務(wù)完成后,做一些操作。比如具有順序性要求的生產(chǎn)者消費(fèi)者等等。

  示例1  任務(wù)1完成之后執(zhí)行任務(wù)2。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    [self groupTest];}- (void)groupTest {    // 創(chuàng)建一個(gè)組    dispatch_group_t group = dispatch_group_create();    NSLog(@"開始執(zhí)行");    dispatch_async(dispatch_get_global_queue(0, 0), ^{        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{            // 任務(wù)1            // 等待1s一段時(shí)間在執(zhí)行            [NSThread sleepForTimeInterval:1];            NSLog(@"task1 running in %@",[NSThread currentThread]);        });        dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{            // 任務(wù)2            NSLog(@"task2 running in %@",[NSThread currentThread]);        });    });}

  點(diǎn)擊屏幕后,打印如下,可以看到任務(wù)1雖然等待了1s,任務(wù)2也不執(zhí)行,只有任務(wù)1執(zhí)行完畢才執(zhí)行任務(wù)2.

2015-08-28 18:16:05.317 GCDTest[1468:229374] 開始執(zhí)行2015-08-28 18:16:06.323 GCDTest[1468:229457] task1 running in <NSThread: 0x7f8962f16900>{number = 2, name = (null)}2015-08-28 18:16:06.323 GCDTest[1468:229456] task2 running in <NSThread: 0x7f8962c92750>{number = 3, name = (null)}

  示例2,其實(shí)示例1并不常用,真正用到的是監(jiān)控多個(gè)任務(wù)完成之后,回到主線程更新UI,或者做其它事情。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {    [self groupTest];}- (void)groupTest {    // 創(chuàng)建一個(gè)組    dispatch_group_t group = dispatch_group_create();    NSLog(@"開始執(zhí)行");    dispatch_async(dispatch_get_global_queue(0, 0), ^{        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{            // 關(guān)聯(lián)任務(wù)1            NSLog(@"task1 running in %@",[NSThread currentThread]);        });        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{            // 關(guān)聯(lián)任務(wù)2            NSLog(@"task2 running in %@",[NSThread currentThread]);        });        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{            // 關(guān)聯(lián)任務(wù)3            NSLog(@"task3 running in %@",[NSThread currentThread]);        });        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{            // 關(guān)聯(lián)任務(wù)4            // 等待1秒            [NSThread sleepForTimeInterval:1];            NSLog(@"task4 running in %@",[NSThread currentThread]);        });        dispatch_group_notify(group, dispatch_get_main_queue(), ^{            // 回到主線程執(zhí)行            NSLog(@"mainTask running in %@",[NSThread currentThread]);        });    });}

  點(diǎn)擊屏幕后,打印如下,可以看到無論其它任務(wù)然后和執(zhí)行,mainTask等待它們執(zhí)行后才執(zhí)行。

2015-08-28 18:24:14.312 GCDTest[1554:236273] 開始執(zhí)行2015-08-28 18:24:14.312 GCDTest[1554:236352] task3 running in <NSThread: 0x7fa8f1f0c9c0>{number = 4, name = (null)}2015-08-28 18:24:14.312 GCDTest[1554:236354] task1 running in <NSThread: 0x7fa8f1d10750>{number = 2, name = (null)}2015-08-28 18:24:14.312 GCDTest[1554:236351] task2 running in <NSThread: 0x7fa8f1c291a0>{number = 3, name = (null)}2015-08-28 18:24:15.313 GCDTest[1554:236353] task4 running in <NSThread: 0x7fa8f1d0e7f0>{number = 5, name = (null)}2015-08-28 18:24:15.313 GCDTest[1554:236273] mainTask running in <NSThread: 0x7fa8f1c13df0>{number = 1, name = main}

 


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 玉环县| 内黄县| 溧水县| 陕西省| 浪卡子县| 泾源县| 博野县| 邹城市| 怀柔区| 泊头市| 鹤山市| 勐海县| 清苑县| 湾仔区| 南投市| 贵南县| 肥乡县| 文安县| 嘉黎县| 通城县| 博野县| 北海市| 诸暨市| 噶尔县| 阿城市| 德格县| 太湖县| 咸宁市| 西贡区| 历史| 吴桥县| 镇坪县| 嘉义市| 宁蒗| 潜江市| 高阳县| 佳木斯市| 元朗区| 奉贤区| 若尔盖县| 托里县|