GCD中有兩種queue,分別為下面兩種
image.png
生成Dispatch Queue的方法
一:dispatch_queue_create
- 生成Serial Dispatch Queue
image.png
- 生成Concurrent Dispatch Queue
image.png
生成的Dispatch Queue必須由程序員負責釋放,這是因為Dispatch Queue並沒有像 Block那樣具有作為<OC對象>來處理的技術,代碼如下
image.png
- 在通過函數或方法獲取Dispatch Queue 以及其他名稱中含有 create 的API生成的對象時,有必要通過 dispatch_retain函數持有,並在不需要時 dispatch_release釋放
二:Main Dispatch Queue/Global Dispatch Queue
//Main Dispatch Queue 的獲取方法
dispatch_queue_t mainDispatchQueue = dispatch_get_main_queue();
//Global Dispatch Queue(高優先級)的獲取方法
dispatch_queue_t golbalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//Global Dispatch Queue(默認優先級)
dispatch_queue_t golbalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//Global Dispatch Queue(低優先級)
dispatch_queue_t golbalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
//Global Dispatch Queue(後臺優先級)
dispatch_queue_t golbalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
- 對於Main Dispatch Queue和Golbal Dispatch Queue執行dispatch_retain 和 dispatch_release函數不會引起任何變化,也不會有任何問題
-
dispatch_set_target_queue
dispatch_queue_create生成的queue都與默認優先級的global dispatch queue相同執行優先級的線程,如需將其變為後臺優先級可參考下面代碼
dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.atsmart.gcd.MySerialDispatchQueue", NULL);
dispatch_queue_t golbalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
dispatch_set_target_queue(mySerialDispatchQueue, golbalDispatchQueueBackground);
如果在多個serial dispatch queue 中用 dispatch_set_target_queue函數指定某一個serial dispatch queue,那麼原本可以並行執行的多個serial dispatch queue,在目標serial dispatch queue上也只能執行一個處理,示意圖如下(如果有需求需要將多個queue按順序執行可用此方法)
image.png
-
dispatch_afer
iOS多线程中performSelector: 和dispatch_time的不同
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC);
dispatch_after(time, dispatch_get_main_queue(), ^{
NSLog(@"");
});
上面代碼不代表在3秒後就執行,而是3秒後加入到主隊列中
-
dispatch_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(@"blk0");});
dispatch_group_async(group, queue, ^{NSLog(@"blk1");});
dispatch_group_async(group, queue, ^{NSLog(@"blk2");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3");});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
queue是並行隊列,所以blk0,blk1,blk2,blk3不能保證順序執行,但是可以保證done是最後打印出來
也可以僅僅等待全部任務結束
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
-
dispatch_group_wait的另一種用法,隔多少時間判斷裏面任務是否執行完畢
image.png -
dispatch_barrier_async
對於數據庫,我們在寫入的時候要保證不能有多個動作同時進行,因為會
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(@"blk0_for_reading");});
dispatch_group_async(group, queue, ^{NSLog(@"blk1_for_reading");});
dispatch_barrier_async(queue, ^{
NSLog(@"writing");
});
dispatch_group_async(group, queue, ^{NSLog(@"blk2_for_reading");});
dispatch_group_async(group, queue, ^{NSLog(@"blk3_for_readinglk3");});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"done");
});
image.png
dispatch_sync
image.png
image.png
-
容易發生死鎖的幾個例子:
1,主線程正在執行代碼,你又等待主線程執行完畢,所以死鎖
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"hello??");
});
dispatch_queue_t queue = dispatch_queue_create("xxx", NULL);
dispatch_async(queue, ^{
dispatch_sync(queue, ^{
NSLog(@"hello?");
});
});
- dispatch_apply
指定次數將Block加入指定Queue中,並等待全部處理執行完畢,示例代碼如下
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
dispatch_apply([array count], queue, ^(size_t index) {
NSLog(@"%zu:%@",index,[array objectAtIndex:index]);
});
//dispatch_apply函數中處理全部執行完畢
dispatch_async(dispatch_get_main_queue(), ^{
//可執行用戶更新操作等
NSLog(@"done");
});
});
dispatch_suspend/dispatch_resume
可以掛起和重新恢復執行queue
- dispatch semaphore
下面代碼會因為同時很多線程操作數組導致系統奔潰
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSMutableArray *array = [[NSMutableArray alloc]init];
for (int i = 0; i<1000; ++i) {
dispatch_async(queue, ^{
[array addObject:[NSNumber numberWithInt:i]];
});
}
改進如下
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);//保證可訪問array的線程只能有一個
NSMutableArray *array = [[NSMutableArray alloc]init];
for (int i = 0; i<100000; ++i) {
dispatch_async(queue, ^{
//等待semaphore,直到semaphore值大於或者等於1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//第一次我們設置為1所以可以直接下來執行,然後會semaphore減1,現在變為0
[array addObject:[NSNumber numberWithInt:i]];
//執行完後還是0,需要進行加1操作,semaphore
dispatch_semaphore_signal(semaphore);
//semaphore為1後,才可以進行下一次循環
});
}
- dispath_once
一般用來初始化操作,保證在多線程環境下也能安全
Dispatch I/O
`