標籤:gcd 多線程
概要
GCD的全稱是Grand Central Dispatch(譯為中心調度隊列?),可以理解為線程管理隊列,是蘋果公司為多核的並行運算提出的解決方案,能夠根據系統內容自適應線程管理,基本屬於全自動的線程管理。
在GCD裡面,任務需要放到隊列裡面執行,隊列根據自身屬性分發任務執行,不過原則總是FIFO。隊列分為串列和並行隊列,串列隊列是隊列裡面只有一個線程,所以隊列裡面只有一個任務在執行,而並行則會根據系統內容,自動調節線程數,可支援同時多個任務執行。
GCD提供了建立以及擷取隊列的方法,包括擷取全域並發隊列、串列主線程隊列以及建立自己的串列隊列(為什麼沒有建立並發的?個人理解是需要建立並發的和直接使用全域並發的效果一樣)。串列隊列因為同時只能執行一個任務的特點,所以可以滿足某些需要按順序執行任務的工作,用以充當鎖、保護共用資源和資料。
串列隊列
- 主線程隊列
擷取主線程隊列,住主隊列是GCD內建的一種串列隊列,該主隊列的任務會在主線程上執行。// 擷取串列的主線程隊列dispatch_queue_t queue = dispatch_get_main_queue();// 非同步執行任務dispatch_async(queue, ^{ NSLog(@"async-%@"); });// 同步執行任務dispatch_sync(queue, ^{ NSLog(@"sync-%@"); });
- 自訂隊列
// 建立隊列,指定名稱,屬性設為預設即可dispatch_queue_t queue = dispatch_queue_create("my_serial_queue", NULL);// 新增工作到隊列// 如果不是ARC的話,釋放該隊列dispatch_release(queue);
並發隊列
GCD提供的全域並發隊列,供整個應用使用,不需要自己再去建立
GCD提供的全域並發隊列,供整個應用使用,不需要自己再去建立// 擷取全域並發隊列,可以選擇優先順序// #define DISPATCH_QUEUE_PRIORITY_HIGH 2// #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0// #define DISPATCH_QUEUE_PRIORITY_LOW (-2)// #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MINdispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);// 同步執行block任務dispatch_async(queue, ^{ NSLog(@"sync-%@"); });// 非同步執行block任務dispatch_async(queue, ^{ NSLog(@"async-%@"); });// 非同步執行方法任務dispatch_async_f(queue, queue_f);
主要函數列表
// 同步執行任務blockdispatch_sync(dispatch_queue_t queue, dispatch_block_t block);// 以非同步方式執行任務blockdispatch_async(dispatch_queue_t queue, dispatch_block_t block);// 非同步執行程式定義的方法void dispatch_async_f ( dispatch_queue_t queue, void *context, dispatch_function_t work );// 建立串列線程隊列dispatch_queue_t dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);// 手動釋放隊列void dispatch_release ( dispatch_object_t object );// 擷取串列主線程隊列dispatch_queue_t dispatch_get_main_queue ( void );// 擷取全域並發隊列dispatch_queue_t dispatch_get_global_queue ( long identifier, unsigned long flags );// 擷取當前代碼的調度隊列dispatch_queue_t dispatch_get_current_queue ( void );// 延遲非同步執行block,對應的有函數dispatch_after_fvoid dispatch_after ( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block );// 建立一個隊列組dispatch_group_t dispatch_group_create ( void );
程式碼範例
- 自訂串列隊列
- (void)viewDidLoad{ [super viewDidLoad]; // 主線程 NSLog(@"main-%@",[NSThread currentThread]); // 建立串列線程隊列 dispatch_queue_t queue = dispatch_queue_create("my_serial", 0); // 非同步執行任務 dispatch_async(queue, ^{ NSLog(@"async1-%@", [NSThread currentThread]); }); // 同步執行任務 dispatch_sync(queue, ^{ NSLog(@"sync-%@", [NSThread currentThread]); }); // 非同步執行任務 dispatch_async(queue, ^{ NSLog(@"async2-%@", [NSThread currentThread]); });}輸出結果
2015-01-01 15:00:35.213 GCDDemo[10763:14132221] main-<NSThread: 0x7fe192e158c0>{number = 1, name = main}2015-01-01 15:00:35.214 GCDDemo[10763:14132356] async1-<NSThread: 0x7fe192d0b5d0>{number = 2, name = (null)}2015-01-01 15:00:35.214 GCDDemo[10763:14132221] sync-<NSThread: 0x7fe192e158c0>{number = 1, name = main}2015-01-01 15:00:35.214 GCDDemo[10763:14132356] async2-<NSThread: 0x7fe192d0b5d0>{number = 2, name = (null)}因為是串列任務隊列,所以隊列只有一個線程,因此兩個非同步任務擷取的線程資訊一樣其number都是1,而同步任務因為在主線程執行,所以擷取的線程資訊和主線程資訊一樣。此外,因為sync在async2之前,所以asyn要等到syn執行完畢。
- 主線程隊列
- (void)viewDidLoad{ [super viewDidLoad]; // 主線程 NSLog(@"main-%@",[NSThread currentThread]); // 建立串列線程隊列,因為主線程隊列需要在其他線程使用 dispatch_queue_t queue = dispatch_queue_create("my_serial", 0); // 非同步執行任務 dispatch_async(queue, ^{ // 擷取主線程隊列 dispatch_queue_t queue = dispatch_get_main_queue(); // 同步執行任務 dispatch_sync(queue, ^{ NSLog(@"sync-%@", [NSThread currentThread]); }); // 非同步執行任務 dispatch_async(queue, ^{ NSLog(@"async-%@", [NSThread currentThread]); }); });}輸出結果
2015-01-01 15:29:35.856 GCDDemo[10800:14143728] main-<NSThread: 0x7ff7d9f0e920>{number = 1, name = main}2015-01-01 15:29:35.898 GCDDemo[10800:14143728] sync-<NSThread: 0x7ff7d9f0e920>{number = 1, name = main}2015-01-01 15:29:35.900 GCDDemo[10800:14143728] async-<NSThread: 0x7ff7d9f0e920>{number = 1, name = main}從直接結果可以看到擷取的線程資訊都一樣,都是主線程資訊,因為這些代碼都是在主線程裡面執行的。
- 全域隊列
- (void)viewDidLoad{ [super viewDidLoad]; // 主線程 NSLog(@"main-%@",[NSThread currentThread]); // 建立串列線程隊列,因為主線程隊列需要在其他線程使用 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 非同步執行任務 dispatch_async(queue, ^{ NSLog(@"async1-started, %@", [NSThread currentThread]); sleep(arc4random()%10); NSLog(@"async1-finished, %@", [NSThread currentThread]); }); // 非同步執行任務 dispatch_async(queue, ^{ NSLog(@"async2-started, %@", [NSThread currentThread]); sleep(arc4random()%10); NSLog(@"async2-finished, %@", [NSThread currentThread]); }); // 非同步執行任務 dispatch_async(queue, ^{ NSLog(@"async3-started, %@", [NSThread currentThread]); sleep(arc4random()%10); NSLog(@"async3-finished, %@", [NSThread currentThread]); }); // 非同步執行任務 dispatch_sync(queue, ^{ NSLog(@"sync-started, %@", [NSThread currentThread]); sleep(arc4random()%10); NSLog(@"sync-finished, %@", [NSThread currentThread]); });}輸出結果
2015-01-01 15:41:11.802 GCDDemo[10851:14149580] main-<NSThread: 0x7f9cda427820>{number = 1, name = main}2015-01-01 15:41:11.803 GCDDemo[10851:14149580] sync-started, <NSThread: 0x7f9cda427820>{number = 1, name = main}2015-01-01 15:41:11.803 GCDDemo[10851:14149677] async3-started, <NSThread: 0x7f9cda624920>{number = 3, name = (null)}2015-01-01 15:41:11.803 GCDDemo[10851:14149679] async2-started, <NSThread: 0x7f9cda4300c0>{number = 2, name = (null)}2015-01-01 15:41:11.804 GCDDemo[10851:14149680] async1-started, <NSThread: 0x7f9cda608e80>{number = 4, name = (null)}2015-01-01 15:41:12.809 GCDDemo[10851:14149680] async1-finished, <NSThread: 0x7f9cda608e80>{number = 4, name = (null)}2015-01-01 15:41:13.808 GCDDemo[10851:14149679] async2-finished, <NSThread: 0x7f9cda4300c0>{number = 2, name = (null)}2015-01-01 15:41:14.805 GCDDemo[10851:14149580] sync-finished, <NSThread: 0x7f9cda427820>{number = 1, name = main}從執行結果可以三個非同步部分的代碼的nunber都不一樣,而且這些都同時執行,說明在不同的線程同時執行,而同步的線程資訊和主線程資訊相同。
IOS多線程開發之GCD