1. 程式人生 > >iOS GCD多執行緒下載原理

iOS GCD多執行緒下載原理

一、任務和佇列

GCD中有2個核心概念

(1)任務:執行什麼操作

(2)佇列:用來存放任務

GCD的使用就2個步驟

(1)定製任務

(2)確定想做的事情

將任務新增到佇列中,GCD會自動將佇列中的任務取出,放到對應的執行緒中執行

提示:任務的取出遵循佇列的FIFO原則:先進先出,後進後出

二、執行任務

1.GCD中有2個用來執行任務的函式

說明:把右邊的引數(任務)提交給左邊的引數(佇列)進行執行。

(1)用同步的方式執行任務 dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

引數說明:

queue:佇列

block:任務

(2)用非同步的方式執行任務 dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

2.同步和非同步的區別

同步:在當前執行緒中執行

非同步:在另一條執行緒中執行

三、佇列

1.佇列的型別

GCD的佇列可以分為2大型別

(1)併發佇列(Concurrent Dispatch Queue)

可以讓多個任務併發(同時)執行(自動開啟多個執行緒同時執行任務)併發功能只有在非同步(dispatch_async)函式下才有效

(2)序列佇列(Serial Dispatch Queue)

讓任務一個接著一個地執行(一個任務執行完畢後,再執行下一個任務)

2.補充說明

有4個術語比較容易混淆:同步、非同步、併發、序列

同步和非同步決定了要不要開啟新的執行緒

同步:在當前執行緒中執行任務,不具備開啟新執行緒的能力

非同步:在新的執行緒中執行任務,具備開啟新執行緒的能力

併發和序列決定了任務的執行方式

併發:多個任務併發(同時)執行

序列:一個任務執行完畢後,再執行下一個任務

3.序列佇列

GCD中獲得序列有2種途徑

(1)使用dispatch_queue_create函式建立序列佇列

dispatch_queue_t  dispatch_queue_create(const char *label,  dispatch_queue_attr_t attr); // 佇列名稱, 佇列屬性,一般用NULL即可

示例:

dispatch_queue_t queue = dispatch_queue_create("wendingding", NULL); // 建立

dispatch_release(queue); // 非ARC需要釋放手動建立的佇列

(2)使用主佇列(跟主執行緒相關聯的佇列)

主佇列是GCD自帶的一種特殊的序列佇列,放在主佇列中的任務,都會放到主執行緒中執行

使用dispatch_get_main_queue()獲得主佇列

示例:

dispatch_queue_t queue = dispatch_get_main_queue();

4.併發佇列

GCD預設已經提供了全域性的併發佇列,供整個應用使用,不需要手動建立

使用dispatch_get_global_queue函式獲得全域性的併發佇列

dispatch_queue_t dispatch_get_global_queue(dispatch_queue_priority_t priority,unsigned long flags); // 此引數暫時無用,用0即可

示例:

這個引數是留給以後用的,暫時用不上,傳個0。 第一個引數為優先順序,這裡選擇預設的。獲取一個全域性的預設優先順序的併發佇列。

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全域性併發佇列

說明:全域性併發佇列的優先順序

#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高

#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 預設(中)

#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低

#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 後臺

5.各種佇列的執行效果

 

四、程式碼示例

(1)用非同步 併發佇列

複製程式碼
 1 //
 2 //  YYViewController.m
 3 //  08-GCD基本使用
 4 //
 5 //  Created by apple on 14-6-24.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8 
 9 #import "YYViewController.h"
10 
11 @interface YYViewController ()
12 
13 @end
14 
15 @implementation YYViewController
16 
17 - (void)viewDidLoad
18 {
19     [super viewDidLoad];
20     //1.獲得全域性的併發佇列
21    dispatch_queue_t queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
22     //2.新增任務到佇列中,就可以執行任務
23     //非同步函式:具備開啟新執行緒的能力
24     dispatch_async(queue, ^{
25         NSLog(@"下載圖片1----%@",[NSThread currentThread]);
26     });
27     dispatch_async(queue, ^{
28         NSLog(@"下載圖片2----%@",[NSThread currentThread]);
29     });
30     dispatch_async(queue, ^{
31         NSLog(@"下載圖片2----%@",[NSThread currentThread]);
32     });
33 //列印主執行緒
34     NSLog(@"主執行緒----%@",[NSThread mainThread]);
35     
36 }
37 
38 @end
複製程式碼

總結:同時開啟三個子執行緒併發(同時)進行  如果想控制子執行緒的併發數量 GCD可用訊號量來控制

(2)用非同步 序列佇列

複製程式碼
 1 //
 2 //  YYViewController.m
 3 //  09—GCD基本使用2
 4 //
 5 //  Created by apple on 14-6-24.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8 
 9 #import "YYViewController.h"
10 
11 @interface YYViewController ()
12 
13 @end
14 
15 @implementation YYViewController
16 
17 - (void)viewDidLoad
18 {
19     [super viewDidLoad];
20     
21     //列印主執行緒
22     NSLog(@"主執行緒----%@",[NSThread mainThread]);
23     
24     //建立序列佇列
25     dispatch_queue_t  queue= dispatch_queue_create("wendingding", NULL);
26     //第一個引數為序列佇列的名稱,是c語言的字串
27     //第二個引數為佇列的屬性,一般來說序列佇列不需要賦值任何屬性,所以通常傳空值(NULL)
28     
29     //2.新增任務到佇列中執行
30     dispatch_async(queue, ^{
31         NSLog(@"下載圖片1----%@",[NSThread currentThread]);
32     });
33     dispatch_async(queue, ^{
34         NSLog(@"下載圖片2----%@",[NSThread currentThread]);
35     });
36     dispatch_async(queue, ^{
37         NSLog(@"下載圖片2----%@",[NSThread currentThread]);
38     });
39     
40     //3.釋放資源
41 //    dispatch_release(queue);
42 }
43 
44 @end
複製程式碼

總結:會開啟執行緒,只開啟一個執行緒  子執行緒的任務是一個一個的執行

(3)用同步 併發佇列

複製程式碼
 1 //
 2 //  YYViewController.m
 3 //  10-CGD基本使用3
 4 //
 5 //  Created by apple on 14-6-24.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8 
 9 #import "YYViewController.h"
10 
11 @interface YYViewController ()
12 
13 @end
14 
15 @implementation YYViewController
16 /**
17  *  用同步函式往併發佇列中新增任務
18  */
19 - (void)viewDidLoad
20 {
21     [super viewDidLoad];
22     
23     //列印主執行緒
24     NSLog(@"主執行緒----%@",[NSThread mainThread]);
25     
26     //建立序列佇列
27     dispatch_queue_t  queue= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
28 
29     
30     //2.新增任務到佇列中執行
31     dispatch_sync(queue, ^{
32         NSLog(@"下載圖片1----%@",[NSThread currentThread]);
33     });
34     dispatch_sync(queue, ^{
35         NSLog(@"下載圖片2----%@",[NSThread currentThread]);
36     });
37     dispatch_sync(queue, ^{
38         NSLog(@"下載圖片3----%@",[NSThread currentThread]);
39     });
40 }
41 
42 @end
複製程式碼

總結:同步不會開啟新的執行緒(只有一個主執行緒),併發佇列失去了併發的功能 (只有一個主執行緒 上哪同時執行去)

(4)用同步 序列佇列

複製程式碼
 1 //
 2 //  YYViewController.m
 3 //  11—CGD基本使用4
 4 //
 5 //  Created by apple on 14-6-24.
 6 //  Copyright (c) 2014年 itcase. All rights reserved.
 7 //
 8 
 9 #import "YYViewController.h"
10 
11 @interface YYViewController ()
12 
13 @end
14 
15 @implementation YYViewController
16 
17 
18 /**
19  *用同步函式往序列佇列中新增任務
20  */
21 - (void)viewDidLoad
22 {
23     [super viewDidLoad];
24      NSLog(@"用同步函式往序列佇列中新增任務");
25     //列印主執行緒
26     NSLog(@"主執行緒----%@",[NSThread mainThread]);
27     
28     //建立序列佇列
29     dispatch_queue_t  queue= dispatch_queue_create("wendingding", NULL);
30     
31     //2.新增任務到佇列中執行
32     dispatch_sync(queue, ^{
33         NSLog(@"下載圖片1----%@",[NSThread currentThread]);
34     });
35     dispatch_sync(queue, ^{
36         NSLog(@"下載圖片2----%@",[NSThread currentThread]);
37     });
38     dispatch_sync(queue, ^{
39         NSLog(@"下載圖片3----%@",[NSThread currentThread]);
40     });
41 }
42 
43 @end
複製程式碼

總結:不會開啟新的執行緒  效果和同步併發 一樣   壓根就一個主執行緒 只會一條一條的執行 (同步時 不管併發還是序列 都是一樣的效果)

(5)補充

補充:佇列名稱的作用:

將來除錯的時候,可以看得出任務是在哪個佇列中執行的。

(6)總結

說明:同步函式不具備開啟執行緒的能力無論是什麼佇列都不會開啟執行緒

        非同步函式具備開啟執行緒的能力,開啟幾條執行緒由佇列決定序列佇列只會開啟一條新的執行緒,併發佇列會開啟多條執行緒)。

同步函式

(1)併發佇列:不會開執行緒

(2)序列佇列:不會開執行緒

非同步函式

(1)併發佇列:能開啟N條執行緒

(2)序列佇列:開啟1條執行緒

補充:

凡是函式中,各種函式名中帶有create\copy\new\retain等字眼,都需要在不需要使用這個資料的時候進行release。 GCD的資料型別在ARC的環境下不需要再做release。 CF(core Foundation)的資料型別在ARC環境下還是需要做release。               非同步函式具備開執行緒的能力,但不一定會開執行緒