1、概念數組
一、同步異步:
a、同步 dispatch_sync():同步執行會等待當前任務執行完再向下執行
b、異步 dispatch_async():不等待當前任務執行完,而是把任務提交後直接向下執行,不等待提交的任務併發
二、隊列
a、串行隊列:提交到串行隊列的任務會一個一個按順序執行,上一個任務完成後、再執行下一個
建立方式(2種同樣):
一、dispatch_queue_create("tongbu", NULL)
二、dispatch_queue_create("tongbu", DISPATCH_QUEUE_SERIAL);
參數1:隊列標籤 參數2:隊列類型(併發)
三、dispatch_get_main_queue() 主隊列也是串行隊列
b、併發隊列:提交到併發隊列的任務對併發執行,每一個任務從提交的那一時刻起都會爲它建立一個線
程,且沒法肯定哪個任務先完成。
建立方式(2種同樣):
一、dispatch_get_global_queue(0, 0)//獲取系統的全局併發隊列
其中,參數1 有如下可選
DISPATCH_QUEUE_PRIORITY_HIGH //2
DISPATCH_QUEUE_PRIORITY_DEFAULT //0 通常選這個便可
DISPATCH_QUEUE_PRIORITY_LOW //-2
DISPATCH_QUEUE_PRIORITY_BACKGROUND // INT16_MIN ( -32768)
二、dispatch_queue_create("tongbu", DISPATCH_QUEUE_CONCURRENT)//本身建立
參數1:隊列標籤 參數2:隊列類型(併發)
特別提醒:dispatch_queue_create 每執行一次就會建立一個新對象,
dispatch_queue_t queue1 = dispatch_queue_create("tongbu", NULL);
dispatch_queue_t queue2= dispatch_queue_create("tongbu", NULL);
此時queue1 != queue2
因此使用時若是想要使用同一隊列,必定要將其存儲起來
!併發隊列 執行時,並不必定會將添加到隊列的任務所有一塊兒執行,而是處理數量取決於系統的狀態(CPU核數,負載。。)先執行前幾個,好比一次性添加了10000個任務到併發隊列,他可能因爲負載緣由只併發執行了第40個,當根據執行狀況再併發後續任務app
2、使用
同步異步與隊列結合使用異步
連續添加十個任務
組合1:同步 + 串行
無心義,連續添加十個任務,會加一個執行一個,第一個執行完,執行加入第二個
組合2:異步 + 串行
十個任務是按順序添加,可是因爲是異步添加,不會影響 "結束"的執行,同時,隊列時串行隊列,因此會挨個執行
組合3:同步 + 併發
無心義,覺得他會等待添加的任務完成在繼續下一步
組合4:異步 + 併發
每一個任務都會開啓新線程去併發執行,至關因而個任務同時併發執行,且不會阻塞當前程序async
3、函數方法
一、 dispatch_barrier_async函數
dispatch_queue_t queue = dispatch_queue_create("tongbu", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue, readFile); dispatch_async(queue, readFile); //會等上面提交的任務完成後再去寫,寫完後才繼續執行下面的提交任務,防止了讀寫競爭 dispatch_barrier_async(queue, writeFile); dispatch_async(queue, readFile); dispatch_async(queue, readFile);
這樣,多個read不會互相影響,提升了讀性能,且不影響寫操做(注意上面的是併發隊列)性能
二、掛起/恢復
注意:它的原理相似於引用計數,一個queue若是調用N次dispatch_suspend,那麼要想恢復,就須要調用N次dispatch_resume才能夠繼續,並且dispatch_resume函數不能隨意調用,只有當前隊列被掛起後才能夠對它使用該函數,不然會報錯spa
dispatch_queue_t queue = dispatch_queue_create("tongbu", NULL); dispatch_suspend(queue);//掛起隊列 dispatch_resume(queue);//恢復隊列
三、定時器線程
//dispatchQueue:該定時器任務在哪一個隊列執行 //intervalInSeconds: 間隔時間 //leewayInSeconds :設置爲0便可 dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, <#dispatchQueue#>); dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, <#intervalInSeconds#> * NSEC_PER_SEC, <#leewayInSeconds#> * NSEC_PER_SEC); dispatch_source_set_event_handler(timer, ^{ //do something ... }); //一次暫停對應一次開始,默認建立完成timer時是暫停的,原理見上一節 //開始(不暫停時不能隨意調用) dispatch_resume(timer); //暫停 dispatch_suspend(timer); //銷燬 dispatch_source_cancel(_timer);
須要注意:要持有 timer 和 queue,不能讓其銷燬,不然定時器失效。
四、dispatch_semaphore_t 信號量
異步的向數組中添加對象會產生內存問題,須要進行鎖處理,可使用dispatch_semaphore_t信號量機制實現code
- (void)test1 { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//併發隊列 NSMutableArray *array = [[NSMutableArray alloc] init]; for (int i = 0; i < 10000; ++i) { dispatch_async(queue, ^{ [array addObject:[NSNumber numberWithInteger:i]];//這裏會產生內存問題 }); } NSLog(@"完成"); }
使用dispatch_semaphore_t
- (void)test2 { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NSMutableArray *array = [[NSMutableArray alloc] init]; //信號量 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); for (int i = 0; i < 10000; ++i) { dispatch_async(queue, ^{ //一、該函數會阻塞,等待直到semaphore計數 >= 1, 而後 內部將計數減1,而後該函數執行完返回 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); //二、執行到此處時, semaphore計數爲0,表明沒有線程修改array [array addObject:[NSNumber numberWithInteger:i]]; //三、處理結束,修改信號量semaphore 加1,若是有dispatch_semaphore_wait函數等待,那麼最早等待的那個線程就先執行 dispatch_semaphore_signal(semaphore); }); } NSLog(@"完成"); }
dispatch_semaphore_t,是一個持有計數的信號
//建立信號 設置信號量總數 dispatch_semaphore_t semaphore = dispatch_semaphore_create(5); //釋放一個信號,semaphore信號計數 +1 dispatch_semaphore_signal(semaphore); //等待信號,當信號計數 >= 1 時就能夠繼續向下執行,同時 它將計數 進行減1 操做,,不然一直等待 //參數2 爲超時時間, //函數返回result: 0 表明success 信號計數 >=1, 非0 表明超時了,信號計數 <1 long result = dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
適用於有限資源的訪問限制
五、Group
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); //添加任務到組 dispatch_group_async(group, queue, ^{ NSLog(@"任務1"); }); dispatch_group_async(group, queue, ^{ NSLog(@"任務2"); }); dispatch_group_async(group, queue, ^{ NSLog(@"任務3"); [NSThread sleepForTimeInterval:5]; }); //任務1,2,3都執行完後才執行該任務 dispatch_group_notify(group, queue, ^{ NSLog(@"最後打印"); }); dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC); //wait函數會阻塞當前線程,直到超時或者group提早執行完成,也能夠將等待時間設置爲DISPATCH_TIME_NOW,當即返回結果,不會阻塞 // result: 0 表明已完成, 非0 未完成,已超時 long result = dispatch_group_wait(group, time); NSLog(@"%ld", result);
六、dispatch_apply
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //按指定次數將block追加到queue //會阻塞當前線程,等待任務完成 dispatch_apply(10, queue, ^(size_t i) { NSLog(@"%zu", i); }); NSLog(@"最後打印");