GCD

GCD的簡單易用,很容易愛不釋手今艺。今天趁機梳理一下GCD相關(guān)知識。

線程爵卒、任務(wù)和隊列

首先來認識一下隊列和任務(wù)
引自:行走的少年郎

任務(wù):就是執(zhí)行操作的意思虚缎,換句話說就是你在線程中執(zhí)行的那段代碼。在GCD中是放在block中的技潘。執(zhí)行任務(wù)有兩種方式:同步執(zhí)行異步執(zhí)行。兩者的主要區(qū)別是:是否具備開啟新線程的能力千康。

  • 同步執(zhí)行(sync):只能在當(dāng)前線程中執(zhí)行任務(wù)享幽,不具備開啟新線程的能力
  • 異步執(zhí)行(async):可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力

隊列:隊列用來管理線程拾弃,也就是線程池值桩,控制線程的創(chuàng)建和執(zhí)行。這里的隊列指任務(wù)隊列豪椿,即用來存放任務(wù)的隊列奔坟。隊列是一種特殊的線性表,采用FIFO(先進先出)的原則搭盾,即新任務(wù)總是被插入到隊列的末尾咳秉,而讀取任務(wù)的時候總是從隊列的頭部開始讀取。每讀取一個任務(wù)鸯隅,則從隊列中釋放一個任務(wù)澜建。在GCD中有兩種隊列:串行隊列并發(fā)隊列

  • 并發(fā)隊列(Concurrent Dispatch Queue):可以讓多個任務(wù)并發(fā)(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù))并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
  • 串行隊列(Serial Dispatch Queue):讓任務(wù)一個接著一個地執(zhí)行(一個任務(wù)執(zhí)行完畢后蝌以,再執(zhí)行下一個任務(wù))炕舵。

線程:可并發(fā)執(zhí)行的,擁有最小系統(tǒng)資源跟畅,共享進程資源的基本調(diào)度單位咽筋。
共用堆,自有棧(官方資料說明iOS主線程棧大小為1M徊件,其它線程為512K)奸攻。
并發(fā)執(zhí)行進度不可控,對非原子操作易造成狀態(tài)不一致虱痕,加鎖控制又有死鎖的風(fēng)險舞箍。

何為GCD

百度一下
Grand Central Dispatch (GCD)是Apple開發(fā)的一個多核編程的較新的解決方法。它主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對稱多處理系統(tǒng)皆疹。它是一個在線程池模式的基礎(chǔ)上執(zhí)行的并行任務(wù)疏橄。在Mac OS X 10.6雪豹中首次推出,也可在IOS 4及以上版本使用。

優(yōu)點
  • 讓程序平行的排列各個任務(wù)捎迫,根據(jù)當(dāng)前的系統(tǒng)資源來合理的安排和分配任務(wù)
  • 能充分利用多核CUP資源
  • 自動管理線程的生命周期晃酒,程序員脫離了手動管理線程的苦海

使用

1、創(chuàng)建隊列
  • 串行隊列:
    使用dispatch_queue_create(const char * label, dispatch_queue_attr_t attr),label 參數(shù)表示此隊列的標(biāo)識符窄绒,調(diào)試的時候可以用到贝次,第二個參數(shù)attr是類型標(biāo)識符,創(chuàng)建串行隊列時使用DISPATCH_QUEUE_SERIAL,創(chuàng)建并發(fā)隊列時使用DISPATCH_QUEUE_CONCURRENT彰导。
//創(chuàng)建一個串行隊列
dispatch_queue_t serialQueue = dispatch_queue_create("com.luqiuan", DISPATCH_QUEUE_SERIAL);

程序開始運行時會自己創(chuàng)建一個主線程放在主隊列中蛔翅,主隊列也是一個串行隊列,主隊列里只存在一個主線程位谋,我們的大部分代碼邏輯都可以在主線程里面處理山析,如果沒有特殊要求(比如耗時操作)我們一般在不需要創(chuàng)建其他線程來增加程序的復(fù)雜度√透福可以用dispatch_get_main_queue()來獲取主隊列笋轨。

  • 并發(fā)隊列
    并發(fā)隊列的創(chuàng)建與串行相似,只需要改變第二個參數(shù)即可
//創(chuàng)建一個并發(fā)隊列
dispatch_queue_t concurrentQueue = dispatch_queue_create("com.luqiuan", DISPATCH_QUEUE_CONCURRENT);

還可以使用dispatch_get_global_queue來創(chuàng)建全局并發(fā)隊列赊淑。GCD默認提供了全局的并發(fā)隊列爵政,需要傳入兩個參數(shù)。第一個參數(shù)表示隊列優(yōu)先級陶缺,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT钾挟。第二個參數(shù)暫時沒用,用0即可饱岸。

2等龙、 任務(wù)的創(chuàng)建方法
// 同步執(zhí)行任務(wù)創(chuàng)建方法
dispatch_sync(queue, ^{
     NSLog(@"%@",[NSThread currentThread]); 
    // 這里放任務(wù)代碼
});
// 異步執(zhí)行任務(wù)創(chuàng)建方法
dispatch_async(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);
    // 這里放任務(wù)代碼
});

雖然使用GCD只需兩步,但是既然我們有兩種隊列伶贰,兩種任務(wù)執(zhí)行方式蛛砰,那么我們就有了四種不同的組合方式。這四種不同的組合方式是
并發(fā)隊列 + 同步執(zhí)行 : 不會創(chuàng)建新線程黍衙,任務(wù)加入隊列時會立馬串行執(zhí)行
并發(fā)隊列 + 異步執(zhí)行 : 具備創(chuàng)建新線程的能力泥畅,先將任務(wù)加入隊列后再開始并行執(zhí)行
串行隊列 + 同步執(zhí)行 : 不會創(chuàng)建新線程,先將任務(wù)加入隊列后再串行執(zhí)行
串行隊列 + 異步執(zhí)行 : 具備創(chuàng)建新線程的能力琅翻,先將任務(wù)加入隊列后再串行執(zhí)行
主隊列 + 同步執(zhí)行 : 不會創(chuàng)建新線程位仁,任務(wù)串行執(zhí)行
主隊列 + 異步執(zhí)行 : 不會創(chuàng)建新線程,任務(wù)串行執(zhí)行

GCD其他功能

1方椎、延時操作
//延時執(zhí)行
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"延時兩秒");
    });
2聂抢、保證代碼執(zhí)行的唯一性
//保證代碼只執(zhí)行一次
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"這段代碼只執(zhí)行一次");
    });
3、GCD快讀迭代
//GCD快讀迭代棠众,當(dāng)我們用for循環(huán)便利一個數(shù)組時琳疏,一般會按順序一個一個便利數(shù)組元素有决,使用GCD迭代可以提高速率,同時遍歷多個元素
    dispatch_queue_t ser1 = createQueue();
    
    NSArray *arr = @[@"一",@"二",@"三",@"四",@"五",@"六",@"七",@"八",@"九"];
    
    dispatch_apply(9, ser1, ^(size_t index) {
        NSLog(@"%@",arr[index]);
    });
4空盼、GCD的柵欄方法

當(dāng)我們需要等待并發(fā)隊列中兩個異步任務(wù)都完成時书幕,才執(zhí)行某一操作時,可以使用GCD的柵欄dispatch_barrier_async揽趾,柵欄就像一個判斷器只有當(dāng)隊列中柵欄前面的所有任務(wù)執(zhí)行完成時台汇,才會執(zhí)行后面的任務(wù)。柵欄只能在用來同一個隊列中篱瞎,如果是不同隊列中的任務(wù)苟呐,我們可以只用GCD隊列組,稍后介紹俐筋。

NSLog(@"========begin===");
    dispatch_queue_t serQueue = createQueue();
    dispatch_async(serQueue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"第一個任務(wù)%d",i);
            sleep(4);
        }
    });
    
    dispatch_async(serQueue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"第二個任務(wù)%d",i);
            sleep(1);
        }
    });
    //用同步的話會阻塞主線程,所以采用異步執(zhí)行
    dispatch_barrier_async(serQueue,^{
        NSLog(@"柵欄柵欄--------------");
    });
    
    dispatch_async(serQueue, ^{
        for (int i = 0; i < 3; i++) {
            NSLog(@"第三個任務(wù)%d",i);
            sleep(1);
        }
    });
    
    NSLog(@"========end=====");
4牵素、GCD隊列組

上面說的是等待同一隊列中不同的并發(fā)任務(wù)執(zhí)行完,而隊列組我們可以用于等待不同隊列中的任務(wù)執(zhí)行完時成時再執(zhí)行某一操作校哎,直接上代碼:

//GCD隊列組两波,當(dāng)我們需要等兩個耗時操作完成時再回到指定隊列工作時瞳步,我們可以使用GCD隊列組
    dispatch_group_t gcdGroup = dispatch_group_create();
    dispatch_queue_t serQueue = dispatch_queue_create("com.luqiuan", DISPATCH_QUEUE_SERIAL);
    //serQueue隊列中的任務(wù)1
    dispatch_group_async(gcdGroup, serQueue, ^{
        NSLog(@"第一個耗時操作");
        sleep(3);
    });
    //全局隊列中的任務(wù)2
    dispatch_group_async(gcdGroup, dispatch_get_global_queue(0, 0), ^{
        sleep(2);
        NSLog(@"第二個耗時操作");
        sleep(3);
    });
    //任務(wù)1和任務(wù)2都完成時闷哆,回到主線程執(zhí)行
    dispatch_group_notify(gcdGroup, dispatch_get_main_queue()   , ^{
        NSLog(@"回到主線程");
    });
5、GCD設(shè)置上下文和清理函數(shù)
//設(shè)置上下文
void dispatch_set_context(dispatch_object_t object, void *context);
//獲取上下文
void *dispatch_get_context(dispatch_object_t object);
//清理函數(shù)单起,當(dāng) queue 的引用計數(shù)到達 0 時執(zhí)行清理函數(shù)
void dispatch_set_finalizer_f(dispatch_object_t object,dispatch_function_t finalizer);

代碼

// 當(dāng) queue 的引用計數(shù)到達 0 時執(zhí)行清理函數(shù)
void finalizerFunction(void *context) {
    char *theData = (char *)context;
    printf("myFinalizerFunction - data = %s\n", theData);
    // 具體清理細節(jié)可以另寫一個函數(shù)
    myCleanUpDataContextFunction(theData);
}

// 具體清理細節(jié)
void myCleanUpDataContextFunction(char *data) {
    printf("myCleanUpDataContextFunction - data = %s\n", data);
}

dispatch_queue_t createQueue(){
    
    char *data = "我是一個字符串";
    dispatch_queue_t serialQueue = dispatch_queue_create("com.luqiuan", DISPATCH_QUEUE_CONCURRENT);
    if (serialQueue) {
        dispatch_set_context(serialQueue, data);
        dispatch_set_finalizer_f(serialQueue, &finalizerFunction);
    }
    return serialQueue;
}

void main(){
    dispatch_queue_t serialQueue = createQueue();
    char *name = dispatch_get_context(serialQueue); 
    NSLog(@"==%@",[NSString stringWithCString:name encoding:NSUTF8StringEncoding]);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末抱怔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嘀倒,更是在濱河造成了極大的恐慌屈留,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件测蘑,死亡現(xiàn)場離奇詭異灌危,居然都是意外死亡,警方通過查閱死者的電腦和手機碳胳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門勇蝙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人挨约,你說我怎么就攤上這事味混。” “怎么了诫惭?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵翁锡,是天一觀的道長。 經(jīng)常有香客問我夕土,道長馆衔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮哈踱,結(jié)果婚禮上荒适,老公的妹妹穿的比我還像新娘。我一直安慰自己开镣,他們只是感情好刀诬,可當(dāng)我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著邪财,像睡著了一般陕壹。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上树埠,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天糠馆,我揣著相機與錄音,去河邊找鬼怎憋。 笑死又碌,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的绊袋。 我是一名探鬼主播毕匀,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼癌别!你這毒婦竟也來了皂岔?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤展姐,失蹤者是張志新(化名)和其女友劉穎躁垛,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體圾笨,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡教馆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了擂达。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片土铺。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖谍婉,靈堂內(nèi)的尸體忽然破棺而出舒憾,到底是詐尸還是另有隱情,我是刑警寧澤穗熬,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布镀迂,位于F島的核電站,受9級特大地震影響唤蔗,放射性物質(zhì)發(fā)生泄漏探遵。R本人自食惡果不足惜窟赏,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望箱季。 院中可真熱鬧涯穷,春花似錦、人聲如沸藏雏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽掘殴。三九已至赚瘦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奏寨,已是汗流浹背起意。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留病瞳,地道東北人揽咕。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像套菜,于是被迫代替她去往敵國和親亲善。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,576評論 2 349

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