iOS多線程實現3-GCD,ios多線程3-gcd

來源:互聯網
上載者:User

iOS多線程實現3-GCD,ios多線程3-gcd

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

一、介紹

  GCD,英文全稱是Grand Central Dispatch(功能強悍的中央調度器),基於C語言編寫的一套多線程開發機制,因此使用時會以函數形式出現,且大部分函數以dispatch開頭,雖然是C語言的但相對於蘋果其它多線程實現方式,抽象層次更高,使用起來也更加方便。

  它是蘋果為應對多核的並行運算提出的解決方案,它會自動利用多核進行並發處理和運算,且線程由系統自動管理(調度、運行),無需程式員參與,使用起來非常方便。

二、任務和隊列

  GCD有兩個核心:任務和隊列。

  任務:要執行的操作或方法函數,隊列:存放任務的集合,而我們要做的就是將任務添加到隊列然後執行,GCD會自動將隊列中的任務按先進先出的方式取出並交給對應線程執行。注意任務的取出是按照先進先出的方式,這也是隊列的特性,但是取出後的執行順序則不一定,下面會詳細討論。

  1 任務

  可以簡單的認為是一個操作,一個函數,一個方法等等,在實際的開發中大多是以block的形式,使用起來也更加靈活。block使用詳見:http://www.cnblogs.com/mddblog/p/4754190.html

  2 隊列

  有兩種隊列:串列隊列和並行隊列。串列隊列:同步執行,在當前線程執行;並行隊列:可由多個線程非同步執行,但任務的取出還是FIFO的。

    隊列建立,根據函數第二個參數來建立串列或並行隊列。

// 參數1 隊列名稱// 參數2 隊列類型 DISPATCH_QUEUE_SERIAL/NULL串列隊列,DISPATCH_QUEUE_CONCURRENT代表並行隊列// 下面代碼為建立一個串列隊列,也是實際開發中用的最多的dispatch_queue_t serialQ = dispatch_queue_create("隊列名", NULL);

  另外系統提供了兩種隊列:全域隊列和主隊列。

    全域隊列屬於並行隊列,只不過已由系統建立的沒有名字,且在全域可見(可用)。擷取全域隊列:

/* 取得全域隊列 第一個參數:線程優先順序,設為預設即可,個人習慣寫0,等同於預設 第二個參數:標記參數,目前沒有用,一般傳入0 */serialQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    主隊列屬於串列隊列,也由系統建立,只不過運行在主線程(UI線程)。擷取主隊列:

// 擷取主隊列serialQ = dispatch_get_main_queue();

  3 執行方式-2種

  同步執行和非同步執行。

    同步執行:不會開啟線程,在當前線程執行。

    非同步執行:gcd管理的線程池中有空閑線程就會從隊列中取出任務執行,會開啟線程。

  下面為實現同步和非同步函數,函數功能為:將任務添加到隊列並執行。

/* 同步執行 第一個參數:執行任務的隊列:串列、並行、全域、主隊列 第二個參數:block任務 */void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);// 非同步執行void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

三、幾種類型

  很明顯兩種執行方式,兩種隊列。那麼就有4種情況:串列隊列同步執行、串列隊列非同步執行、並行隊列同步執行、並行隊列非同步執行。哪一種會開啟新的線程?開幾條?是否並發?記憶起來比較繞,但是只要抓住基本的就可以,為了方便理解,現分析如下:

  1)串列隊列,同步執行-----串列隊列意味著順序執行,同步執行意味著不開啟線程(在當前線程執行)

  2)串列隊列,非同步執行-----串列隊列意味著任務順序執行,非同步執行說明要開線程, (如果開多個線程的話,不能保證串列隊列順序執行,所以只開一個線程)

  3)並行隊列,非同步執行-----並行隊列意味著執行順序不確定,非同步執行意味著會開啟線程,而並行隊列又允許不按順序執行,所以系統為了提高效能會開啟多個線程,來隊列取任務(隊列中任務取出仍然是順序取出的,只是線程執行無序)。

  4)並行隊列,同步執行-----同步執行意味著不開線程,則肯定是順序執行

  5)主線程中主隊列,同步執行-----程式執行不出來(死結) ;原因:主隊列,如果主線程正在執行代碼,就不調度任務;同步執行:一直執行第一個任務直到結束。兩者互相等待造成死結。

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

四、常用舉例

  1 線程間通訊

  比如,為了提高使用者體驗,我們一般在其他線程(非主線程)下載圖片或其它網路資源,下載完成後我們要更新UI,而UI更新必須在主線程執行,所以我們經常會使用:

// 同步執行,會阻塞指導下面block中的代碼執行完畢dispatch_sync(dispatch_get_main_queue(), ^{    // 主線程,UI更新});// 非同步執行dispatch_async(dispatch_get_main_queue(), ^{    // 主線程,UI更新});

  2 其它常用

  全域隊列,實現並發:

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

五、Dispatch Group調度組

  使用調度組,可以輕鬆實現在一些任務完成後,做一些操作。比如具有順序性要求的生產者消費者等等。

  樣本1  任務1完成之後執行任務2。

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

  點擊螢幕後,列印如下,可以看到任務1雖然等待了1s,任務2也不執行,只有任務1執行完畢才執行任務2.

2015-08-28 18:16:05.317 GCDTest[1468:229374] 開始執行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,其實樣本1並不常用,真正用到的是監控多個任務完成之後,回到主線程更新UI,或者做其它事情。

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

  點擊螢幕後,列印如下,可以看到無論其它任務然後和執行,mainTask等待它們執行後才執行。

2015-08-28 18:24:14.312 GCDTest[1554:236273] 開始執行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}

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.