GCD的简介及应用
OC中有三種多線程,分別是NSThread、NSOperationQueue、及GCD;三者使用的輕重度依次是GCD-->NSOperationQueue-->NSThread;這里就不詳細對比。
GCD這要是采用C語言語法配合Block實現,可以實現同步、異步操作;運行并行、串行隊列;同步鎖,單例、延時等。
Dispatch Queue
| Serial Dispatch Queue | 串行隊列 |
| Concurrent Dispatch Queue | 并行隊列 |
系統的Queue:
GCD中提供兩個系統的Queue一個是mian_queue,一個是global_queue;兩者分別屬于串行隊列及并行隊列;
dispatch_queue_t main_queue =? dispatch_get_main_queue();dispatch_queue_t global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);自定義Queue
dispatch_queue_t serial_queue =?dispatch_queue_create("DISPATCH_QUEUE_SERIAL", QUEUESERIAL);dispatch_queue_t concurrent_queue = dispatch_queue_create("QUEUECONCURRENT", DISPATCH_QUEUE_CONCURRENT);async與sync
async為異步操作,不用等待執行結果,sync為同步操作,等待執行結果。
async可以異步開啟多線程隊列,包括串行隊列、并行隊列,也可以異步返回主線程刷新UI:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{//多線程操作dispatch_async(dispatch_get_main_queue(), ^{//主線程刷新UI? ? ? ? ? ??}); });備注:異步會出現數據不同步的情況,需要實現數據的同步處理。
sync一般常配合串行隊列實現同步鎖:
dispatch_queue_t serial_queue =? dispatch_queue_create("QUEUESERIAL", DISPATCH_QUEUE_SERIAL);dispatch_sync(serial_queue, ^{});備注:同步鎖不能用于該串行隊列的線程操作中,不然會導致線程堵塞。
suspend/resume
dispatch_suspend(queue);掛起指定的Dispatch_Queue
dispatch_resume(queue);恢復指定的Dispatch_Queue
Dispatch_Group
GCD中的Group可以解決異步隊列的數據不同步問題,實現同個并行隊列的回調監聽,并在隊列執行完之后調用notify通知
dispatch_group_t group = dispatch_group_create();dispatch_queue_t queue = dispatch_queue_create("CONCURRENTQUEUE", DISPATCH_QUEUE_CONCURRENT);dispatch_group_async(_group, _queue, ^{ sleep(2); NSLog(@"1");??});dispatch_group_async(_group, _queue, ^{ sleep(2); NSLog(@"2");??});dispatch_group_notify(_group, dispatch_get_main_queue(), ^{ NSLog(@"3");?});如果不是用同一個GCD_Queue的多線程操作,可以用group_enter和group_leave實現,類似于計數器
dispatch_group_enter(_group); //+1?dispatch_group_leave(_group); //-1dispatch_group_notify(_group, dispatch_get_main_queue(), ^{?});//為0時觸發通知回調group中的wait方法也會阻塞線程,但也隨著enter和leave的平衡(計數為0時)而失效
dispatch_group_wait(_group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)));//阻塞線程2秒鐘?dispatch_barrier
?dispatch_barrier:在并行隊列中添加串行操作,實現欄柵化。
dispatch_queue_t queue = dispatch_queue_create("QUEUECONCURRENT", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{ sleep(1);NSLog(@"1");? });? ??dispatch_async(queue, ^{sleep(1);NSLog(@"2");? });dispatch_barrier_async(queue, ^{sleep(1);NSLog(@"3");? });dispatch_barrier_async(queue, ^{sleep(1);NSLog(@"4");? });?? ?dispatch_async(queue, ^{sleep(1);NSLog(@"5");? });dispatch_async(queue, ^{sleep(1);NSLog(@"6"); });備注:先執行 1、2并行操作,再執行3、4串行操作,最后執行5、6并行操作
dispatch_semaphore
類似于鎖的作用,通過設置信號量限定當前訪問資源的最大線程量,先調用wait(降低)再調用signal(提高),信號量小于0時,處于鎖住狀態,無法訪問資源。
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1); dispatch_queue_t quene = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//任務1dispatch_async(quene, ^{dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSLog(@"run task 1");sleep(1);NSLog(@"complete task 1");dispatch_semaphore_signal(semaphore); });//任務2dispatch_async(quene, ^{dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSLog(@"run task 2");sleep(1);NSLog(@"complete task 2");dispatch_semaphore_signal(semaphore); });//任務3dispatch_async(quene, ^{dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);NSLog(@"run task 3");sleep(1);NSLog(@"complete task 3");dispatch_semaphore_signal(semaphore); }); }// 信號量為1,依次執行Task1、Task2、Task3。阻塞當前線程,等待異步事件執行完成
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{sleep(1);dispatch_semaphore_signal(semaphore); });dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);// 在wait之后阻塞當前線程,在signal之后恢復執行dispatch_once
單例模式,確保應用只執行一次once中的代碼塊。
static NSArray* dataArr;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{dataArr = @[@"1",@"2",@"3"];});dispatch_after
延時處理,類似于NSTimer,不過只是單次,不能設置循環
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{//延時兩秒 });dispatch_source?
事件源處理,一般應用于定時器,具有高精準度,不會受到RunLoopMode切換的影響(default->Tracking)。NSTimer(有一定的誤差)、CADisplayLink(高精準度,適用于高頻的動畫效果),NSTimer與CADisplayLink都會受到RunLoopMode切換的影響。
@implementation GCDSource- (instancetype)initWithTimeInterval:(NSTimeInterval)timeInterval repeats:(BOOL)repeats timerBlock:(void(^)(void))timerBlock {self = [super init];if (self) {_timeInterval = timeInterval;_repeats = repeats;self.timerBlock = timerBlock;[self initTimer];}return self; }- (void)initTimer {dispatch_queue_t timerQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_queue_t blockQueue = dispatch_get_main_queue();self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timerQueue);dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), _timeInterval * NSEC_PER_SEC, 0);dispatch_source_set_event_handler(_timer, ^{dispatch_async(blockQueue, ^{self.timerBlock();});if (_repeats == NO) {[self stopTimer];}});dispatch_resume(_timer); }- (void)pauseTimer {if(self.timer){dispatch_suspend(_timer);} }- (void)resumeTimer {if(self.timer){dispatch_resume(_timer);} }- (void)stopTimer {if(self.timer){dispatch_source_cancel(_timer);_timer = nil;} }- (void)dealloc {[self stopTimer]; }@enddispatch_target
使queue的優先級與目標queue相同
如果將多個串行的queue使用dispatch_set_target_queue指定到了同一目標,那么著多個串行queue在目標queue上就是同步執行的,不再是并行執行。
dispatch_queue_t targetQueue = dispatch_queue_create("targetQueue", DISPATCH_QUEUE_SERIAL);dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL);dispatch_queue_t queue3 = dispatch_queue_create("queue3", DISPATCH_QUEUE_SERIAL);dispatch_set_target_queue(queue1, targetQueue);dispatch_set_target_queue(queue2, targetQueue);dispatch_async(queue1, ^{sleep(1);NSLog(@"1");});dispatch_async(queue2, ^{sleep(1);NSLog(@"2");});dispatch_async(queue3, ^{sleep(1);NSLog(@"3"); });備注:三個不同的串行隊列,會作為一個串行隊列的方式執行,依次輸出1,2,3
GCD對象化封裝
GCDObjective
總結
- 上一篇: 数据数值转换factorize和dumm
- 下一篇: 获奖感言的建议