GCD

(1) GCD基本概念

01 GCD
    1.1 全稱是Grand Central Dispatch喳魏,可譯為“牛逼的中樞調(diào)度器”
純C語言,提供了非常多強(qiáng)大的函數(shù)

    1.2 GCD的優(yōu)勢
        GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案送火,自動利用更多的CPU內(nèi)核(比如雙核誉简、四核)
        GCD會自動管理線程的生命周期(創(chuàng)建線程喘先、調(diào)度任務(wù)钾恢、銷毀線程)
        程序員只需要告訴GCD想要執(zhí)行什么任務(wù)翘鸭,不需要編寫任何管理線程的代碼

02 兩個核心概念-隊(duì)列和任務(wù)
    2.1 任務(wù):需要執(zhí)行的操作;任務(wù)是最小單位滴铅,任務(wù)一旦執(zhí)行,就必須執(zhí)行完畢就乓;線程不同汉匙,線程可以暫停拱烁,阻塞,強(qiáng)制死亡噩翠。
    2.2 隊(duì)列:用來存放任務(wù)戏自,任務(wù)的取出遵循隊(duì)列的FIFO原則:先進(jìn)先出,后進(jìn)后出
    2.3 任務(wù)伤锚、隊(duì)列浦妄、線程、同異步函數(shù)的關(guān)系:
        2.3.1任務(wù):一個具體的任務(wù)(操作)
        2.3.2隊(duì)列:任務(wù)列表及執(zhí)行順序(并發(fā)隊(duì)列:無序執(zhí)行见芹;串行隊(duì)列:順序執(zhí)行)
        2.3.3線程:車間工人剂娄,執(zhí)行任務(wù)的個人(實(shí)際由CPU處理)
        2.3.4同步與異步函數(shù):決定執(zhí)行任務(wù)的總?cè)藬?shù)
        2.3.5總結(jié):按什么順序由多少人(線程)執(zhí)行多少任務(wù)。

03 同步和異步(影響線程數(shù))
    3.1 同步:只能在當(dāng)前線程中執(zhí)行任務(wù)玄呛,不具備開啟新線程的能力;在當(dāng)前線程執(zhí)行并且在所在隊(duì)列中馬上執(zhí)行(重要)
    3.2 異步:可以在新的線程中執(zhí)行任務(wù)阅懦,具備開啟新線程的能力(具備不代表一定開啟新的線程),不要求馬上執(zhí)行

04 GCD的隊(duì)列類型(影響執(zhí)行順序)
    4.1 并發(fā)隊(duì)列(Concurrent Dispatch Queue)
        4.1.1 自動開啟多個線程同時(shí)執(zhí)行任務(wù)
        4.1.2 并發(fā)功能只有在異步函數(shù)下才有效
    4.2 串行隊(duì)列(Serial Dispatch Queue)
        4.2.1 一個任務(wù)執(zhí)行完畢后徘铝,再執(zhí)行下一個任務(wù)
    4.3 主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
        4.3.1 主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列
        4.3.2 在主隊(duì)列中的任務(wù)耳胎,都會在主線程中執(zhí)行
        4.3.3 主線程主隊(duì)列執(zhí)行的任務(wù)中存在同步函數(shù)+主隊(duì)列任務(wù),會導(dǎo)致死鎖(因?yàn)橹麝?duì)列中的當(dāng)前任務(wù)并沒有完成惕它,它的下一個任務(wù)是新增的同步函數(shù)+主隊(duì)列任務(wù)怕午,并且要求所在線程立即執(zhí)行所在隊(duì)列(所在隊(duì)列不是當(dāng)前隊(duì)列),系統(tǒng)無法在隊(duì)列中的當(dāng)前任務(wù)沒處理完成前切換任務(wù)淹魄,導(dǎo)致死鎖)

05 線程執(zhí)行組合:
    01 異步函數(shù)+并發(fā)隊(duì)列:開啟多條線程郁惜,并發(fā)執(zhí)行任務(wù)
    02 異步函數(shù)+串行隊(duì)列:開啟一條線程,串行執(zhí)行任務(wù)
    03 同步函數(shù)+并發(fā)隊(duì)列:不開線程甲锡,串行執(zhí)行任務(wù)
    04 同步函數(shù)+串行隊(duì)列:不開線程兆蕉,串行執(zhí)行任務(wù)
    05 異步函數(shù)+主隊(duì)列:不開線程,在主線程中串行執(zhí)行任務(wù)
    06 同步函數(shù)+主隊(duì)列:不開線程缤沦,在主線程中串行執(zhí)行任務(wù)(注意死鎖發(fā)生)
    07 使用sync函數(shù)往當(dāng)前串行隊(duì)列中添加任務(wù)虎韵,會卡住當(dāng)前的串行隊(duì)列

(2)GCD基本使用【重點(diǎn)】

  • 步驟(以什么順序由多少人(線程)執(zhí)行多少任務(wù)):
    • 創(chuàng)建或獲取隊(duì)列

    • 通過同步函數(shù)或異步函數(shù)或函數(shù)方式將任務(wù)添加到隊(duì)列中

01 同步函數(shù)與異步函數(shù)
    1.1 用同步(sync)的函數(shù)執(zhí)行任務(wù)
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
queue:隊(duì)列
block:任務(wù)
    1.2 用異步(async)的函數(shù)執(zhí)行任務(wù)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
queue:隊(duì)列
block:任務(wù)
    1.3 通過函數(shù)的方式來封裝任務(wù)
    /*
     第一個參數(shù):隊(duì)列
     第二個參數(shù):要調(diào)用函數(shù)需要傳遞的參數(shù)
     第三個參數(shù):函數(shù)
     */
    NSString *str = @"wendingding";
    //橋接--(__)
    dispatch_async_f(queue, (__bridge void *)(str), run);

02 并發(fā)隊(duì)列與串行隊(duì)列
    2.1 手動創(chuàng)建并發(fā)隊(duì)列
    /*
     第一個參數(shù):C語言的字符串 隊(duì)列名稱
     第二個參數(shù):隊(duì)列的類型
     DISPATCH_QUEUE_CONCURRENT--并發(fā)
     DISPATCH_QUEUE_SERIAL---串行隊(duì)列
     */
dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", DISPATCH_QUEUE_CONCURRENT);

    2.2 獲得全局并發(fā)隊(duì)列
        2.2.1GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列,供整個應(yīng)用使用缸废,可以無需手動創(chuàng)建
    /*
     第一個參數(shù):隊(duì)列的優(yōu)先級
     第二個參數(shù):此參數(shù)是留給未來使用包蓝,暫時(shí)無用,用0即可
     DISPATCH_QUEUE_CONCURRENT--并發(fā)
     DISPATCH_QUEUE_SERIAL---串行隊(duì)列
     */
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

        2.2.2 全局并發(fā)隊(duì)列的優(yōu)先級
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺

    2.3 串行隊(duì)列
    /*
     第一個參數(shù):C語言的字符串 隊(duì)列名稱
     第二個參數(shù):隊(duì)列的類型
     DISPATCH_QUEUE_CONCURRENT--并發(fā)
     DISPATCH_QUEUE_SERIAL---串行隊(duì)列或傳遞NULL
     */
dispatch_queue_t queue = dispatch_queue_create("com.520it.queue", NULL);

    2.4 使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
//使用dispatch_get_main_queue()獲得主隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();

(3)GCD線程間通信

 //0.獲取一個全局的隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    //1.先開啟一個線程企量,把下載圖片的操作放在子線程中處理
    dispatch_async(queue, ^{

       //2.下載圖片
        NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];

        NSLog(@"下載操作所在的線程--%@",[NSThread currentThread]);

        //3.回到主線程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
           self.imageView.image = image;
           //打印查看當(dāng)前線程
            NSLog(@"刷新UI---%@",[NSThread currentThread]);
        });

    });

(4)GCD其它常用函數(shù)


    01 柵欄函數(shù)(控制任務(wù)的執(zhí)行順序)
    dispatch_barrier_sync(queue, ^{
        NSLog(@"--dispatch_barrier_sync-");
    });
//在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行测萎,而且它后面的任務(wù)等它執(zhí)行完成之后才會執(zhí)行
//這個queue不能是全局的并發(fā)隊(duì)列,蘋果文檔沒做解釋


    02 延遲執(zhí)行(延遲·控制在哪個線程執(zhí)行)
        2.1 第一種方法——使用GCD函數(shù)
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"---%@",[NSThread currentThread]);
    });

        2.2 第二種方法——調(diào)用NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒后再調(diào)用self的run方法

        2.3 第三種方法——使用NSTimer
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(test) userInfo:nil repeats:NO];


    03 一次性代碼(注意不能用在懶加載)
    -(void)once
    {
        //整個程序運(yùn)行過程中只執(zhí)行一次梁钾,默認(rèn)是線程安全的
        //onceToken用來記錄該部分的代碼是否被執(zhí)行過
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{

            NSLog(@"-----");
        });
    }

    04 快速迭代(開多個線程并發(fā)完成迭代操作)
       dispatch_apply(subpaths.count, queue, ^(size_t index) {
       // index順序不確定
       // 內(nèi)部開多個線程并發(fā)完成迭代操作绳泉,有可能包括主線程
       // 雖然是多線程,但一樣會卡住線程
       // 應(yīng)用場景:快速處理某些不算太耗時(shí)的操作姆泻,并回到主線程進(jìn)行某些操作零酪。
       // 如果處理耗時(shí)操作冒嫡,建議使用并發(fā)+異步函數(shù),手動回到主線程刷新四苇,不建議使用這種方法
    });

    05 隊(duì)列組(同柵欄函數(shù))
    //創(chuàng)建隊(duì)列組
    dispatch_group_t group = dispatch_group_create();
    //多次執(zhí)行耗時(shí)的異步操作
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 執(zhí)行1個耗時(shí)的異步操作
});
    //隊(duì)列組中的任務(wù)執(zhí)行完畢之后孝凌,執(zhí)行該函數(shù)
    dispatch_group_notify(dispatch_group_t group,
    dispatch_queue_t queue,
    dispatch_block_t block);

(5)快速迭代剪切文件

-(void)apply
{
    //1.創(chuàng)建文件管理者
    NSFileManager *manager = [NSFileManager defaultManager];
    NSString *from = @"/Users/a1/Desktop/form";
    NSString *to = @"/Users/a1/Desktop/to";

    //2.獲得要剪切的所有文件
    NSArray *subPaths =[manager subpathsAtPath:from];
    NSLog(@"%@",subPaths);

    NSInteger count = subPaths.count;

    //3.創(chuàng)建并發(fā)隊(duì)列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    // 4.快速迭代
    // 內(nèi)部不能使用continue
    /*
     第一個參數(shù):循環(huán)的次數(shù)
     第二個參數(shù):隊(duì)列
     第三個參數(shù):block 在里面執(zhí)行迭代任務(wù)  index:索引
     */
    dispatch_apply(count, queue, ^(size_t index) {
        //剪切圖片
        //4.1獲得文件名稱
        NSString *fileName = subPaths[index];

        //4.2 拼接要剪切的文件的全路徑
        NSString *fullPath1 = [from stringByAppendingPathComponent:fileName];

        //4.3 拼接文件要剪切到哪個地方的全路徑
        NSString *fullpath2 = [to stringByAppendingPathComponent:fileName];

        //4.4 執(zhí)行剪切
        [manager moveItemAtPath:fullPath1 toPath:fullpath2 error:nil];

        NSLog(@"%@---%@---%@",[NSThread currentThread],fullPath1,fullpath2);
    });
}

(6)GDC其他內(nèi)容

01 使用Crearte函數(shù)創(chuàng)建的并發(fā)隊(duì)列和全局并發(fā)隊(duì)列的主要區(qū)別:
    1. 全局并發(fā)隊(duì)列在整個應(yīng)用程序中本身是默認(rèn)存在的,并且對應(yīng)有高優(yōu)先級月腋、默認(rèn)優(yōu)先級蟀架、低優(yōu)先級和后臺優(yōu)先級一共四個并發(fā)隊(duì)列,我們只是選擇其中的一個直接拿來用榆骚。
    2. Crearte函數(shù)是實(shí)打?qū)嵉膹念^開始去創(chuàng)建一個隊(duì)列片拍。

02 GCD內(nèi)存管理
    1. 在iOS6.0之前,在GCD中凡是使用了帶Crearte和retain的函數(shù)在最后都需要做一次release操作妓肢。而主隊(duì)列和全局并發(fā)隊(duì)列不需要我們手動release捌省。
    2. 在iOS6.0之后GCD已經(jīng)被納入到了ARC的內(nèi)存管理范疇中,即便是使用retain或者create函數(shù)創(chuàng)建的對象也不再需要開發(fā)人員手動釋放碉钠,我們像對待普通OC對象一樣對待GCD就OK纲缓。

03 在使用柵欄函數(shù)的時(shí)候,蘋果官方明確規(guī)定柵欄函數(shù)只有在和使用create函數(shù)自己的創(chuàng)建的并發(fā)隊(duì)列一起使用的時(shí)候才有效(沒有給出具體原因)

04 其它區(qū)別涉及到XNU內(nèi)核的系統(tǒng)級線程編程喊废,不一一列舉
05 給出一些參考資料(可以自行研究):

GCDAPI:https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_queue_create

Libdispatch版本源碼:http://www.opensource.apple.com/source/libdispatch/libdispatch-187.5/
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祝高,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子污筷,更是在濱河造成了極大的恐慌工闺,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颓屑,死亡現(xiàn)場離奇詭異斤寂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)揪惦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來罗侯,“玉大人器腋,你說我怎么就攤上這事」辰埽” “怎么了纫塌?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長讲弄。 經(jīng)常有香客問我措左,道長,這世上最難降的妖魔是什么避除? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任怎披,我火速辦了婚禮胸嘁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凉逛。我一直安慰自己性宏,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布状飞。 她就那樣靜靜地躺著毫胜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诬辈。 梳的紋絲不亂的頭發(fā)上酵使,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機(jī)與錄音焙糟,去河邊找鬼口渔。 笑死,一個胖子當(dāng)著我的面吹牛酬荞,可吹牛的內(nèi)容都是我干的搓劫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼混巧,長吁一口氣:“原來是場噩夢啊……” “哼枪向!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起咧党,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤秘蛔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后傍衡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體深员,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年蛙埂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了倦畅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡绣的,死狀恐怖叠赐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情屡江,我是刑警寧澤芭概,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站惩嘉,受9級特大地震影響罢洲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜文黎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一惹苗、第九天 我趴在偏房一處隱蔽的房頂上張望殿较。 院中可真熱鬧,春花似錦鸽粉、人聲如沸斜脂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至妹卿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間片任,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工蔬胯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留对供,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓氛濒,卻偏偏與公主長得像产场,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子舞竿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評論 2 355

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