iOS-----使用GCD實現多線程,ios-----gcd多線程

來源:互聯網
上載者:User

iOS-----使用GCD實現多線程,ios-----gcd多線程
使用GCD實現多線程GCD的兩個核心概念如下:

隊列

隊列負責管理開發人員提交的任務,GCD隊列始終以FIFO(先進先出)的方式來處理任務---但

由於任務的執行時間並不相同,因此先處理的任務並一定先結束。隊列既可是串列隊列,也可是並發隊列則可同時處理多個任務,因此將會有多個任務並發執行。

隊列底層會維護一個線程池來處理使用者提交的任務,線程池的作用就是執行隊列管理的任務。串列隊列底層的線程池只要維護一個線程即可,並發隊列的底層則需要維護多個線程。

任務

任務就是使用者提交給隊列的工作單元,這些任務將會提交給隊列底層維護的線程池執行,因此這些任務會以多線程的方式執行。

使用GCD只要遵守兩個步驟即可

1.

建立隊列

2.

將任務提交給隊列

     
建立隊列

GCD的隊列可分為兩種

串列隊列

串列隊列底層的線程只要一個線程,因此只提供一個線程用來執行任務,所以後一個任必須等到前一個任務執行結束才能開始執行

並發隊列

線程池提供多個線程來執行任務,所以可以按FIFO(先進先出)的順序並發啟動、執行多個並發任務。

函數

 

涉及一個dispatch_queue_t,這種類型就代表一個隊列。

程式可以建立如下幾種隊列

 

擷取系統預設的全域並發隊列可通過如下程式碼完成:

dispatch_queue_t  queue = dispatch_get_global_queue(

DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

擷取系統主線程關聯的串列隊列可通過如下程式碼完成:

dispatch_queue_t  queue = dispatch_get_main_queue();

如果將任務提交給主線程關聯的串列隊列,那麼就相當於直接在程式主線程中去執行該任務。

建立串列隊列可通過如下程式碼完成:

dispatch_queue_t  queue = dispatch_queue_create(“LCiOS.queue”,

DISPATCH_QUEUE_SERIAL);

   如果將多個任務提交給串列隊列,多個任務只能按順序執行,必須等前一個任務完成後,才能開始執行後一個任務。

建立並發隊列可通過如下程式碼完成:

dispatch_queue_t queue = dispacth_queue_create(“LCiOS.queue”

, DISPATCH_QUEUE_CONCURRENT);

如果將多個任務提交給並發隊列,並發隊列可以按FIFO(先進先出)的順序啟動多個並發執行的任務,由於任務的耗時間長度短並不相同,因此後提交的任務完全可能先完成。

得到隊列之後,接下來就可以將任務提交給隊列,並由隊列底層管理的線程池來執行這些任務。

 

     
非同步提交任務

iOS提供了如下函數來向隊列提交任務。下面這些函數很多都有兩個版本:一個接收代碼塊作為參數的版本,

一個接收函數作為參數的版本----其中接收函數作為參數的函數名最後多了_f尾碼,而且會多一個參數,用於向函數傳入應用程式定義的上下文。

 

  1 ViewController.m  2   3 @implementation ViewController  4   5 // 定義2個隊列  6   7 dispatch_queue_t  serialQueue;  8   9 dispatch_queue_t  concurrentQueue; 10  11 - (void)viewDidLoad 12  13 { 14  15    [super viewDidLoad]; 16  17    // 建立串列隊列 18  19 serialQueue = dispatch_queue_create(“LCiOS.queue”,DISPATCH_QUEUE_SERIAL); 20  21 // 建立並發隊列 22  23 concurrentQueue = dispatch_queue_create(“LCiOS.queue”,DISPATCH_QUEUE_CONCURRENT); 24  25 } 26  27 - (IBAction)serial:(id)sender 28  29 { 30  31   // 依次將兩個代碼塊提交給串列隊列 32  33   // 必須等到第1個代碼塊完成後,才能執行第2個代碼塊 34  35   dispatch_async(serialQueue,  ^(void) 36  37 { 38  39    for(int i = 0; i < 100; i++) 40  41 { 42  43    NSLog(@”%@====%d”, [NSThread  currentThread], i); 44  45 } 46  47 }); 48  49 dispatch_async(serialQueue,  ^(void) 50  51 { 52  53    for(int i = 0; i < 100; i++) 54  55 { 56  57    NSLog(@”%@-----%d”, [NSThread  currentThread], i); 58  59 } 60  61 }); 62  63 } 64  65 - (IBAction)concurrent:(id)sender 66  67 { 68  69   // 依次將兩個代碼塊提交給並發隊列 70  71   // 兩個代碼塊可以並發執行 72  73   dispatch_async(concurrentQueue,  ^(void) 74  75 { 76  77    for(int i = 0; i < 100; i ++) 78  79 { 80  81    NSLog(@”%@====%d”, [NSThread  currentThread] ,  i); 82  83 } 84  85 }); 86  87 dispatch_async(concurrentQueue,  ^(void) 88  89 { 90  91    for(int i = 0; i < 100; i ++) 92  93 { 94  95    NSLog(@”%@-----%d”, [NSThread  currentThread] ,  i); 96  97 } 98  99 });100 101 }102 103 @end

 

    上面程式中的兩行粗體字代碼建立了兩個隊列,其中第1個隊列是串列隊列,第2個隊列是並發隊列。接下來程式實現了serial:和concurrent:兩個事件處理方法,在serial:方法中使用dispatch_async()函數向串列隊列以非同步方式提交兩個代碼塊,在concurrent:方法中使用dispatch_async()函數向並發隊列以非同步方式提交兩個代碼塊。

  編譯、運行該程式,如果使用者單擊的按鈕控製程序向串列隊列提交兩個代碼塊,將可以在控制台看到如所示的輸出。

如果

如果使用者單擊的按鈕控製程序向並發隊列提交兩個代碼塊,將可以在控制台看到如所示的輸出

 

使用G

CD下載圖片

   

 1 ViewController.m 2  3 @implementation ViewController 4  5 - (void)viewDidLoad 6  7 { 8  9    [super viewDidLoad];10 11 }12 13 - (IBAction)downImag:(id)sender14 15 {16 17 // 將代碼塊提交給系統的全域並發隊列18 19 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH , 0) , ^(void){20 21     NSString* url = @” http://images.cnblogs.com/cnblogs_com/congli0220/752817/o_%e4%b8%8b%e8%bd%bd.jpg”;22 23       // 從網路擷取資料24 25        NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];26 27      // 將網路資料初始化為UIImage對象28 29     UIImage *image = [[UIImage alloc] initWithData:data];30 31     if(image != nil)32 33     {34 35       // 將代碼塊提交給主線程關聯的隊列,該代碼將會由主線程完成36 37       dispatch_async(dispatch_get_main_queue(), ^{38 39        self.iv.image = image;40 41 });// 142 43 }44 45 else46 47 {48 49   NSLog(@”---下載圖片出現錯誤---”);50 51 }52 53 });54 55 }56 57 @end

 

說明

 該程式中的代碼會將代碼塊提交給系統預設的全域並發隊列,該代碼塊就會負責從網路下載圖片。由於該代碼塊同樣會在多線程中執行,因此程式的“1”號代碼處再次使用了dispatch_async()函數將更新介面上UI控制項的代碼交給主線程執行.

同步提交任務

dispatch_sync()函數則會以同步方式提交代碼塊,該函數必須等到代碼塊執行結束才會返回.如果程式使用該函數先後提交了兩個代碼塊(即使提交給並發隊列),也必須等第1個任務完成後才會開始執行第2個任務.

例如如下樣本的視圖控制器類的實現部分代碼

 1 ViewController.m 2  3 @implementation ViewController 4  5 - (void)viewDidLoad 6  7 { 8  9    [super viewDidLoad];10 11 }12 13 - (IBAction)clicked:(id)sender14 15 {16 17   // 以同步方式先後提交兩個代碼塊18 19   dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){20 21              for(int i = 0 ; i < 100; i++)22 23              {24 25                  NSLog(@”%@====%d”, [NSThread currentThread] , i);26 27     [NSThread sleepForTimeInterval:0.1];28 29 }30 31 });32 33 // 必須等第1次提交的代碼塊執行完成後,dispatch_sync()函數才會返回34 35 // 程式才會執行到這裡,才能提交第2個代碼塊36 37 dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0  ), ^(void){38 39      for(int i = 0 ; i < 100; i ++)40 41      {42 43        NSLog(@”%@------%d”, [NSThread  currentThread] , i);44 45        [NSThread  sleepForTimeInterval:0.1];46 47 }48 49 });50 51 }52 53 @end

 

說明

   上面程式使用dispatch_sync()函數以同步方式提交代碼塊,該函數必須等到所提交的代碼塊執行完成後才會返回,因此該函數雖然啟動另外的線程來執行代碼塊,但它依然會阻塞主線程.

上面程式先後兩次使用dispatch_sync()函數來提交代碼塊,因此程式必須等到第1次使用dispatch_sync()函數提交的代碼塊執行完成後,該函數才會返回,程式才會執行第2次提交.

只有等到兩次提交的代碼塊都執行完成後,clicked:事件處理方法才能返回----表明事件響應執行完成.如果使用者單擊激發該事件的按鈕,該按鈕將會一直處於高亮狀態,直到兩個代碼塊執行完成

多次執行的任務

  dispatch_apply()函數將控制提交的代碼塊重複執行多次,如果該代碼塊被提交給並發隊列,系統可以使用多個線程並發執行同一個代碼塊.

   下面樣本程式在介面上包含了一個按鈕,當使用者單擊該按鈕時將會使用dispatch_apply()函數將代碼塊提交給並發隊列,並控制該代碼塊執行多次.

   下面是該樣本的視圖控制器類的實現部分代碼.

 1 ViewController.m 2  3 @implementation ViewController 4  5 - (void)viewDidLoad 6  7 { 8  9    [super viewDidLoad];10 11 }12 13 - (IBAction)clicked:(id)sender14 15 {16 17    // 控制碼執行5次18 19    dispatch_apply(5 , dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)20 21 // time形參代表當前正在執行第幾次22 23 ,^(size_t time)24 25 {26 27    NSLog(@===執行【%lu】次===%@”, time , [NSThread currentThread]);28 29 });30 31 }32 33 @end

 

說明

上面程式中的粗體字代碼使用dispatch_apply()函數控制提交的代碼塊執行5次,該函數所需的代碼塊略有不同,該代碼塊可以帶一個參數,該參數代表當前正在執行第幾次.

 

 

只執行一次的任務

dispatch_once()函數將控制提交的代碼塊在整個應用的生命週期內最多隻執行一次----只有第1次提交該代碼塊時,

該代碼塊才會獲得執行的機會.而且dispatch_once()函數無須傳入隊列,這意味著系統將直接用主線程執行該函數提交的代碼塊.

dispatch_once()函數執行時需要傳入一個dispatch_once_t類型(本質就是long型整數)的指標(即predicate參數),

該指標變數用於判斷該代碼塊是否已經執行過.

下面樣本程式在介面上包含了一個按鈕,當使用者單擊該按鈕時激發的事件處理方法將會使用dispatch_once()函數提交代碼塊,

將代碼塊提交給主線程執行,因此該代碼塊可能阻塞主線程.但當使用者再次單擊該按鈕時,dispatch_once()函數提交的代碼塊不會再執行.

程式碼片段

 1 ViewController.m 2  3 @implementation ViewController 4  5 - (void)viewDidLoad 6  7 { 8  9    [super viewDidLoad];10 11 }12 13 - (IBAction)clicked:(id)sender14 15 {16 17   static dispatch_once_t onceToken;18 19   dispatch_once(&onceToken, ^{20 21 NSLog(@”==執行代碼塊==”);22 23 // 線程暫停3秒24 25 [NSThread sleepForTimeInterval:3];26 27 });28 29 }30 31 @end

 

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.