簡述:
說道線程,離不開并行和串行,所謂并行,就是100賽跑,每個賽道就是一個線程,每個線程之間互不影響,同時都可以運行事件,就是10個賽道都可以有運動員跑步了,誰跑的慢或者跑的快,都不影響其他的人。串行就不一樣了,串行是1個賽道10個運動員再跑接力賽,第一個跑到終點第二個在接著跑,依次類推,前邊的不走,后邊的也走不了的,所以串行上面的事件是一個一個運行的,同時只能是一個人再跑。
在iOS或者OS里面,一般用GCD就能處理較多的事務,下面就談一下GCD的用法。
什么是GCD?
全稱是Grand Central Dispatch,可譯為“牛逼的中樞調度器”
純C語言,提供了非常多強大的函數
methodList info
//獲取主線程 就是更新UI的線程
dispatch_queue_t dispatch_get_main_queue(void);
//獲取全局隊列
dispatch_queue_t dispatch_get_global_queue( long identifier, unsigned long flags);
//創建一個隊列 名字是label 屬性可以寫為NULL
dispatch_queue_t dispatch_queue_create( const char *label dispatch_queue_attr_t attr);
dispatch_release(queue)//釋放隊列
//獲取代碼現在運行的queue
dispatch_queue_t dispatch_get_current_queue( void);
//獲取隊列的名字
const char * dispatch_queue_get_label(dispatch_queue_t queue);
//異步把代碼塊block交給queue隊列中處理
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
// 同步將block加入到queue中并且執行。
void dispatch_sync( dispatch_queue_t queue, dispatch_block_t block);
//block 在指定時間在queue中執行
void dispatch_after( dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
//幾個調度事件同事加入到queue中去,最好是全局隊列才行。
void dispatch_apply( size_t iterations, dispatch_queue_t queue, void (^block)( size_t));
// block 是否執行過
void dispatch_once( dispatch_once_t *predicate, dispatch_block_t block);
//在分組group中的queue隊列執行block
void dispatch_group_async( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
//創建線程分組
dispatch_group_t dispatch_group_create( void);
//分組的計數+1
void dispatch_group_enter( dispatch_group_t group);
//分組計數 -1
void dispatch_group_leave( dispatch_group_t group);
// 當分組中的事務處理完了執行block
void dispatch_group_notify( dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);
//等待timeout時間后執行 group中的事務
long dispatch_group_wait( dispatch_group_t group, dispatch_time_t timeout);
//并行狀態下 queue前面的并行事務處理完成了在執行block,然后執行下邊的并行代碼
//比如 ABCDEF D事務等到ABC都完成了在執行EF事務的
void dispatch_barrier_async( dispatch_queue_t queue, dispatch_block_t block);
實戰演練全局隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
//異步執行
dispatch_sync(dispatch_get_main_queue(), ^{
//這里面更新UI
});
});
dispatch_sync(queue, ^{
//同步執行
});
自定義隊列
dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_SERIAL);
//
//#define DISPATCH_QUEUE_SERIAL 同步隊列
//#define DISPATCH_QUEUE_CONCURRENT 異步隊列
dispatch_async(queue, ^{
NSLog(@"下載圖片1=====%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下載圖片2=====%@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
NSLog(@"下載圖片3=====%@",[NSThread currentThread]);
});
NSLog(@"main:%@",[NSThread mainThread]);
當queue屬性為 DISPATCH_QUEUE_CONCURRENT輸出:
**2016-03-28 16:53:25.848 GCD_Demo[12338:347984] ****下載圖片****3=====<NSThread: 0x7fabda100250>{number = 4, name = (null)}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347982] ****下載圖片****2=====<NSThread: 0x7fabda2008a0>{number = 3, name = (null)}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347937] main:<NSThread: 0x7fabd8c04ee0>{number = 1, name = main}**
**2016-03-28 16:53:25.848 GCD_Demo[12338:347981] ****下載圖片****1=====<NSThread: 0x7fabd8c0a010>{number = 2, name = (null)}** 線程達到了4個
當queue屬性為DISPATCH_QUEUE_SERIAL輸出:
**2016-03-28 16:46:54.501 GCD_Demo[12272:344348] main:<NSThread: 0x7fd379704cf0>{number = 1, name = main}**
**2016-03-28 16:46:54.501 GCD_Demo[12272:344382] ****下載圖片****1=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
**2016-03-28 16:46:54.502 GCD_Demo[12272:344382] ****下載圖片****2=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
**2016-03-28 16:46:54.502 GCD_Demo[12272:344382] ****下載圖片****3=====<NSThread: 0x7fd37971bda0>{number = 2, name = (null)}**
線程只有2個
多個異步線程問題
# 當ABC 3個異步線程,要求前兩個個執行完再去執行后面的三個的時候例子:
dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
NSLog(@"queue1 begin");
sleep(2);
NSLog(@"queue1 end");
});
dispatch_async(queue, ^{
NSLog(@"queue2 begin");
sleep(2);
NSLog(@"queue2 end");
});
dispatch_barrier_sync(queue, ^{
NSLog(@"main:%@",[NSThread mainThread]);
});
dispatch_async(queue, ^{
NSLog(@"queue3 begin");
sleep(2);
NSLog(@"queue3 end");
});
輸出:
**2016-03-28 17:01:01.319 GCD_Demo[12463:353702] queue2 begin**
**2016-03-28 17:01:01.319 GCD_Demo[12463:353703] queue1 begin**
**2016-03-28 17:01:03.324 GCD_Demo[12463:353703] queue1 end**
**2016-03-28 17:01:03.324 GCD_Demo[12463:353702] queue2 end**
**2016-03-28 17:01:03.325 GCD_Demo[12463:353657] main:<NSThread: 0x7f97ea604bf0>{number = 1, name = main}**
**2016-03-28 17:01:03.325 GCD_Demo[12463:353702] queue3 begin**
**2016-03-28 17:01:05.330 GCD_Demo[12463:353702] queue3 end**
線程分組
# 當多個任務同時進行的時候,也可以用group,ABCD任務進行完成的時候,最后在執行task。
dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"task1 begin");
sleep(2);
NSLog(@"task1 end");
});
dispatch_group_async(group, queue, ^{
NSLog(@"task2 begin");
sleep(2);
NSLog(@"task2 end");
});
dispatch_group_notify(group, queue, ^{
NSLog(@"=================");
});
dispatch_group_async(group, queue, ^{
NSLog(@"task3 begin");
sleep(2);
NSLog(@"task3 end");
});
dispatch_group_async(group, queue, ^{
NSLog(@"task4 begin");
sleep(2);
NSLog(@"task4 end");
});
輸出:
**2016-03-28 17:08:45.002 GCD_Demo[12557:357162] task1 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357164] task4 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357161] task2 begin**
**2016-03-28 17:08:45.002 GCD_Demo[12557:357163] task3 begin**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357162] task1 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357163] task3 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357164] task4 end**
**2016-03-28 17:08:47.005 GCD_Demo[12557:357161] task2 end**
**2016-03-28 17:08:47.006 GCD_Demo[12557:357161] =================**
一個組內的所有任務都進行完了才會執行task的函數。
# 分組多任務等待 ABCDEF ,ABCD執行5秒,5秒之后就執行EF任務,不管ABCD是否成功。
dispatch_queue_t queue = dispatch_queue_create("com.apple.fgyong", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
NSLog(@"task1 begin");
sleep(2);
NSLog(@"task1 end");
});
dispatch_group_async(group, queue, ^{
NSLog(@"task2 begin");
sleep(2);
NSLog(@"task2 end");
});
dispatch_group_notify(group, queue, ^{
NSLog(@"=================");
});
dispatch_group_async(group, queue, ^{
NSLog(@"task3 begin");
sleep(6);
NSLog(@"task3 end");
});
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC)));
NSLog(@"all end");
dispatch_group_async(group, queue, ^{
NSLog(@"task4 begin");
sleep(2);
NSLog(@"task4 end");
});
輸出:
# 代碼執行到wait的時候會等待5秒之后再執行wait下邊的代碼,和sleep有點相似。
**2016-03-28 17:26:31.335 GCD_Demo[12745:366983] task3 begin**
**2016-03-28 17:26:31.335 GCD_Demo[12745:366978] task1 begin**
**2016-03-28 17:26:31.335 GCD_Demo[12745:366979] task2 begin**
**2016-03-28 17:26:33.340 GCD_Demo[12745:366978] task1 end**
**2016-03-28 17:26:33.340 GCD_Demo[12745:366979] task2 end**
**2016-03-28 17:26:36.336 GCD_Demo[12745:366894] all end**
**2016-03-28 17:26:36.336 GCD_Demo[12745:366979] task4 begin**
**2016-03-28 17:26:37.340 GCD_Demo[12745:366983] task3 end**
**2016-03-28 17:26:38.342 GCD_Demo[12745:366979] task4 end**
**2016-03-28 17:26:38.342 GCD_Demo[12745:366983] =================**
同時處理多數據不管順序
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
/*! dispatch_apply函數說明
10 *
11 * @brief dispatch_apply函數是dispatch_sync函數和Dispatch Group的關聯API
12 * 該函數按指定的次數將指定的Block追加到指定的Dispatch Queue中,并等到全部的處理執行結束
13 *
14 * @param 10 指定重復次數 指定10次
15 * @param queue 追加對象的Dispatch Queue
16 * @param index 帶有參數的Block, index的作用是為了按執行的順序區分各個Block
17 *
18 */
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%d", index);
});
NSLog(@"done");
輸出:
# 這個和上邊講的分組類似,多事務處理,處理結束后再執行代碼。
# 這個是同步的,代碼按順序執行,分組的是異步執行的block
**2016-03-28 17:36:35.698 GCD_Demo[12857:372458] 1**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372463] 5**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372429] 4**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372464] 6**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372465] 7**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372462] 2**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372457] 0**
**2016-03-28 17:36:35.698 GCD_Demo[12857:372461] 3**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372458] 8**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372429] 9**
**2016-03-28 17:36:35.699 GCD_Demo[12857:372429] done**
參考文章:Grand Central Dispatch (GCD) Reference
GCD提供的接口蠻多的,適用場景還是要熟練掌握,才能運用自如。
更多文章:www.fgyong.cn