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。 非同步函式具備開執行緒的能力,但不一定會開執行緒