GCD的基礎知識html
同步函數+串行隊列ios
//同步函數 + 串行隊列 - (void)syncSerial { NSLog(@"start %s -------%@",__FUNCTION__,[NSThread currentThread]); /* 建立串行隊列 */ dispatch_queue_t queue = dispatch_queue_create("https://teilim.com", DISPATCH_QUEUE_SERIAL); /* 將執行任務加入隊列 */ dispatch_sync(queue, ^{ for (NSInteger i = 0; i<5; i++) { NSLog(@"task A time %lo -----%@", i,[NSThread currentThread]); } }); dispatch_sync(queue, ^{ for (NSInteger i = 0; i<5; i++) { NSLog(@"task B time %lo -----%@", i,[NSThread currentThread]); } }); NSLog(@"finish %s -------%@",__FUNCTION__,[NSThread currentThread]); }
打印內容網絡
2016-11-11 20:16:47.338 MutipleThreadPractice[27817:3509801] start -[GCDDemoViewController syncSerial] -------<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.339 MutipleThreadPractice[27817:3509801] task A time 0 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.339 MutipleThreadPractice[27817:3509801] task A time 1 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] task A time 2 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] task A time 3 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] task A time 4 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] task B time 0 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] task B time 1 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] task B time 2 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] task B time 3 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] task B time 4 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:16:47.340 MutipleThreadPractice[27817:3509801] finish -[GCDDemoViewController syncSerial] -------<NSThread: 0x7ff2a8501790>{number = 1, name = main}
同步函數+併發隊列session
//同步函數 + 併發隊列 - (void)syncConcurrent { NSLog(@"start %s -------%@",__FUNCTION__,[NSThread currentThread]); /* 建立併發隊列 */ dispatch_queue_t queue = dispatch_queue_create("https://teilim.com", DISPATCH_QUEUE_CONCURRENT); /* 將執行任務加入隊列 */ dispatch_sync(queue, ^{ for (NSInteger i = 0; i<5; i++) { NSLog(@"task A time %lo -----%@", i,[NSThread currentThread]); } }); dispatch_sync(queue, ^{ for (NSInteger i = 0; i<5; i++) { NSLog(@"task B time %lo -----%@", i,[NSThread currentThread]); } }); NSLog(@"finish %s -------%@",__FUNCTION__,[NSThread currentThread]); }
打印內容併發
2016-11-11 20:19:35.113 MutipleThreadPractice[27817:3509801] start -[GCDDemoViewController syncConcurrent] -------<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.113 MutipleThreadPractice[27817:3509801] task A time 0 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.114 MutipleThreadPractice[27817:3509801] task A time 1 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.114 MutipleThreadPractice[27817:3509801] task A time 2 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.114 MutipleThreadPractice[27817:3509801] task A time 3 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.115 MutipleThreadPractice[27817:3509801] task A time 4 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.115 MutipleThreadPractice[27817:3509801] task B time 0 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.115 MutipleThreadPractice[27817:3509801] task B time 1 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.117 MutipleThreadPractice[27817:3509801] task B time 2 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.117 MutipleThreadPractice[27817:3509801] task B time 3 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.117 MutipleThreadPractice[27817:3509801] task B time 4 -----<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:19:35.118 MutipleThreadPractice[27817:3509801] finish -[GCDDemoViewController syncConcurrent] -------<NSThread: 0x7ff2a8501790>{number = 1, name = main}
異步函數+串行隊列app
//異步函數 + 串行隊列 - (void)asyncSerial { NSLog(@"start %s -------%@",__FUNCTION__,[NSThread currentThread]); /* 建立串行隊列 */ dispatch_queue_t queue = dispatch_queue_create("https://teilim.com", DISPATCH_QUEUE_SERIAL); /* 將任務加入隊列 */ dispatch_async(queue, ^{ for (NSInteger i = 0; i<5; i++) { NSLog(@"task A time %lo -----%@", i,[NSThread currentThread]); } }); dispatch_async(queue, ^{ for (NSInteger i = 0; i<5; i++) { NSLog(@"task B time %lo -----%@", i,[NSThread currentThread]); } }); NSLog(@"finish %s -------%@",__FUNCTION__,[NSThread currentThread]); }
打印內容異步
2016-11-11 20:20:58.620 MutipleThreadPractice[27817:3509801] start -[GCDDemoViewController asyncSerial] -------<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:20:58.621 MutipleThreadPractice[27817:3509801] finish -[GCDDemoViewController asyncSerial] -------<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:20:58.621 MutipleThreadPractice[27817:3515050] task A time 0 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.622 MutipleThreadPractice[27817:3515050] task A time 1 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.623 MutipleThreadPractice[27817:3515050] task A time 2 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.624 MutipleThreadPractice[27817:3515050] task A time 3 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.626 MutipleThreadPractice[27817:3515050] task A time 4 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.626 MutipleThreadPractice[27817:3515050] task B time 0 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.627 MutipleThreadPractice[27817:3515050] task B time 1 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.627 MutipleThreadPractice[27817:3515050] task B time 2 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.627 MutipleThreadPractice[27817:3515050] task B time 3 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)} 2016-11-11 20:20:58.628 MutipleThreadPractice[27817:3515050] task B time 4 -----<NSThread: 0x7ff2a86bba20>{number = 2, name = (null)}
異步函數+併發隊列async
//異步函數 + 串行隊列 - (void)asyncSerial { NSLog(@"start %s -------%@",__FUNCTION__,[NSThread currentThread]); /* 建立串行隊列 */ dispatch_queue_t queue = dispatch_queue_create("https://teilim.com", DISPATCH_QUEUE_SERIAL); /* 將任務加入隊列 */ dispatch_async(queue, ^{ for (NSInteger i = 0; i<5; i++) { NSLog(@"task A time %lo -----%@", i,[NSThread currentThread]); } }); dispatch_async(queue, ^{ for (NSInteger i = 0; i<5; i++) { NSLog(@"task B time %lo -----%@", i,[NSThread currentThread]); } }); NSLog(@"finish %s -------%@",__FUNCTION__,[NSThread currentThread]); }
打印內容函數
2016-11-11 20:22:17.234 MutipleThreadPractice[27817:3509801] start -[GCDDemoViewController asyncConcurrent] -------<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:22:17.234 MutipleThreadPractice[27817:3509801] finish -[GCDDemoViewController asyncConcurrent] -------<NSThread: 0x7ff2a8501790>{number = 1, name = main} 2016-11-11 20:22:17.234 MutipleThreadPractice[27817:3516618] task A time 0 -----<NSThread: 0x7ff2a8476df0>{number = 3, name = (null)} 2016-11-11 20:22:17.234 MutipleThreadPractice[27817:3516625] task B time 0 -----<NSThread: 0x7ff2a870f6a0>{number = 4, name = (null)} 2016-11-11 20:22:17.236 MutipleThreadPractice[27817:3516618] task A time 1 -----<NSThread: 0x7ff2a8476df0>{number = 3, name = (null)} 2016-11-11 20:22:17.236 MutipleThreadPractice[27817:3516625] task B time 1 -----<NSThread: 0x7ff2a870f6a0>{number = 4, name = (null)} 2016-11-11 20:22:17.237 MutipleThreadPractice[27817:3516618] task A time 2 -----<NSThread: 0x7ff2a8476df0>{number = 3, name = (null)} 2016-11-11 20:22:17.237 MutipleThreadPractice[27817:3516625] task B time 2 -----<NSThread: 0x7ff2a870f6a0>{number = 4, name = (null)} 2016-11-11 20:22:17.238 MutipleThreadPractice[27817:3516618] task A time 3 -----<NSThread: 0x7ff2a8476df0>{number = 3, name = (null)} 2016-11-11 20:22:17.239 MutipleThreadPractice[27817:3516625] task B time 3 -----<NSThread: 0x7ff2a870f6a0>{number = 4, name = (null)} 2016-11-11 20:22:17.239 MutipleThreadPractice[27817:3516618] task A time 4 -----<NSThread: 0x7ff2a8476df0>{number = 3, name = (null)} 2016-11-11 20:22:17.239 MutipleThreadPractice[27817:3516625] task B time 4 -----<NSThread: 0x7ff2a870f6a0>{number = 4, name = (null)}
GCD groupatom
dispatch_group_notify函數用來指定一個額外的block,該block將在group中全部任務完成後執行
-(void)gcdGroup{ 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, ^{ [NSThread sleepForTimeInterval:5]; NSLog(@"finish task 1"); /*加載圖片1 */ }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:1]; NSLog(@"finish task 2"); /*加載圖片2 */ }); dispatch_group_async(group, queue, ^{ [NSThread sleepForTimeInterval:2]; NSLog(@"finish task 3"); /*加載圖片3 */ }); dispatch_group_notify(group, dispatch_get_main_queue(), ^{ NSLog(@"do next step after all the tasks "); // 合併圖片 }); }
打印內容
2016-11-11 20:24:04.883 MutipleThreadPractice[27817:3518196] finish task 2 2016-11-11 20:24:05.883 MutipleThreadPractice[27817:3518197] finish task 3 2016-11-11 20:24:08.887 MutipleThreadPractice[27817:3518158] finish task 1 2016-11-11 20:24:08.887 MutipleThreadPractice[27817:3509801] do next step after all the tasks
GCD Barrier
-(void)gcdBarrier{ dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(concurrentQueue, ^(){ NSLog(@"dispatch-1"); }); dispatch_async(concurrentQueue, ^(){ NSLog(@"dispatch-2"); }); dispatch_barrier_async(concurrentQueue, ^(){ NSLog(@"dispatch-barrier"); }); dispatch_async(concurrentQueue, ^(){ NSLog(@"dispatch-3"); }); dispatch_async(concurrentQueue, ^(){ NSLog(@"dispatch-4"); }); }
打印
2016-11-11 20:25:31.036 MutipleThreadPractice[27817:3519239] dispatch-1 2016-11-11 20:25:31.036 MutipleThreadPractice[27817:3519324] dispatch-2 2016-11-11 20:25:31.037 MutipleThreadPractice[27817:3519324] dispatch-barrier 2016-11-11 20:25:31.038 MutipleThreadPractice[27817:3519324] dispatch-3 2016-11-11 20:25:31.038 MutipleThreadPractice[27817:3519239] dispatch-4
子線程進行下載圖片,完成後在主線程進行UI操做
-(void)backgroundDownloadImage{ NSLog(@"before download image"); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSURL * url = [NSURL URLWithString:@"http://avatar.csdn.net/2/C/D/1_totogo2010.jpg"]; NSData * data = [[NSData alloc]initWithContentsOfURL:url]; UIImage *image = [[UIImage alloc]initWithData:data]; if (data != nil) { dispatch_async(dispatch_get_main_queue(), ^{ self.imageView.image = image; NSLog(@"download the image data"); }); } }); NSLog(@"end download image"); }
打印內容
2016-11-11 20:27:00.944 MutipleThreadPractice[27817:3509801] before download image 2016-11-11 20:27:00.945 MutipleThreadPractice[27817:3509801] end download image 2016-11-11 20:27:01.359 MutipleThreadPractice[27817:3509801] download the image data
多窗口賣票模型
@interface GCDDemoViewController () /*庫存的火車票*/ @property (nonatomic,assign) NSInteger numberOfTickets; /**帳戶餘額*/ @property (nonatomic,assign) float accountBalance; @property (nonatomic,strong) dispatch_queue_t sellTicketQueue; @implementation GCDDemoViewController -(dispatch_queue_t)sellTicketQueue{ if (!_sellTicketQueue) { _sellTicketQueue=dispatch_queue_create("SellTicketQueue", DISPATCH_QUEUE_SERIAL); } return _sellTicketQueue; } - (void)sellTicket:(NSInteger)number { self.numberOfTickets = self.numberOfTickets - 1; self.accountBalance = self.accountBalance + 10; NSLog(@"window == %ld ticket number==%ld balance=%.2f total value=%f", number, (long)self.numberOfTickets, self.accountBalance, self.numberOfTickets * 10 + self.accountBalance); } - (void)sellTicketsWithoutLock { dispatch_queue_t queue1 = dispatch_queue_create("com.sellTicket", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue1, ^{ for (int i = 0; i < 1000; i++) { [NSThread sleepForTimeInterval:0.001]; [self sellTicket:1]; } }); dispatch_async(queue1, ^{ for (int i = 0; i < 1000; i++) { [NSThread sleepForTimeInterval:0.002]; [self sellTicket:2]; } }); dispatch_async(queue1, ^{ for (int i = 0; i < 1000; i++) { [self sellTicket:3]; [NSThread sleepForTimeInterval:0.004]; } }); }
加鎖對競爭性資源的讀寫進行限制
- (void)sellTicketsWithLock { dispatch_queue_t queue1 = dispatch_queue_create("com.sellTicket", DISPATCH_QUEUE_CONCURRENT); dispatch_async(queue1, ^{ for (int i = 0; i < 1000; i++) { @synchronized(self) { [NSThread sleepForTimeInterval:0.001]; [self sellTicket:1]; } } }); dispatch_async(queue1, ^{ for (int i = 0; i < 1000; i++) { @synchronized(self) { [NSThread sleepForTimeInterval:0.002]; [self sellTicket:2]; } } }); dispatch_async(queue1, ^{ for (int i = 0; i < 1000; i++) { @synchronized(self) { [NSThread sleepForTimeInterval:0.004]; [self sellTicket:3]; } } }); }
使用串行隊列進行限制
- (void)sellTicketsWithSerialQueue { dispatch_queue_t queue1 = dispatch_queue_create("com.sellTicket", DISPATCH_QUEUE_CONCURRENT); for (int i = 0; i < 1000; i++) { dispatch_async(queue1, ^{ [NSThread sleepForTimeInterval:0.001]; [self sellTicketInSerialQueue]; }); dispatch_async(queue1, ^{ [NSThread sleepForTimeInterval:0.002]; [self sellTicketInSerialQueue]; }); dispatch_async(queue1, ^{ [NSThread sleepForTimeInterval:0.004]; [self sellTicketInSerialQueue]; }); } } - (void)sellTicketInSerialQueue { dispatch_async(self.sellTicketQueue, ^{ self.numberOfTickets = self.numberOfTickets - 1; self.accountBalance = self.accountBalance + 10; NSLog(@" ticket number==%ld balance=%.2f total value=%f", (long)self.numberOfTickets, self.accountBalance, self.numberOfTickets * 10 + self.accountBalance); }); }
信號量
常見業務場景,
1,多個網絡請求返回之後同時作處理
在異步執行的代碼中,只有當信號量>0時才能繼續執行。這樣能夠控制最大併發的數量。也能夠作異步任務的同步處理。
/建立信號量/ dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); /建立全局並行/ 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(@"處理事件A"); for (int i = 0; i<10000; i++) { NSLog(@"打印i %d",i); } dispatch_semaphore_signal(semaphore); }); dispatch_group_async(group, queue, ^{ NSLog(@"處理事件B"); for (int i = 0; i<10000; i++) { NSLog(@"打印j %d",i); } dispatch_semaphore_signal(semaphore); }); dispatch_group_async(group, queue, ^{ NSLog(@"處理事件C"); for (int i = 0; i<10000; i++) { NSLog(@"打印k %d",i); } dispatch_semaphore_signal(semaphore); }); dispatch_group_async(group, queue, ^{ NSLog(@"處理事件D"); for (int i = 0; i<10000; i++) { NSLog(@"打印l %d",i); } dispatch_semaphore_signal(semaphore); }); dispatch_group_notify(group, queue, ^{ /四個請求對應四次信號等待/ dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); NSLog(@"處理事件E"); });
這個例子,控制了,最大的併發線程數是10.超過10個線程執行的話,就暫時中止加入新的任務。
// 建立隊列組 dispatch_group_t group = dispatch_group_create(); // 建立信號量,而且設置值爲10 dispatch_semaphore_t semaphore = dispatch_semaphore_create(10); dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); for (int i = 0; i < 100; i++) { // 因爲是異步執行的,因此每次循環Block裏面的dispatch_semaphore_signal根本尚未執行就會執行dispatch_semaphore_wait,從而semaphore-1.當循環10此後,semaphore等於0,則會阻塞線程,直到執行了Block的dispatch_semaphore_signal 纔會繼續執行 dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); dispatch_group_async(group, queue, ^{ NSLog(@"%i",i); sleep(2); // 每次發送信號則semaphore會+1, dispatch_semaphore_signal(semaphore); }); }
屢次請求之後綜合處理
- (dispatch_queue_t)uploadImageConcurrentQueue { if (!_uploadImageConcurrentQueue) { _uploadImageConcurrentQueue = dispatch_queue_create( "com.hzt.uploadImageQueue", DISPATCH_QUEUE_CONCURRENT); } return _uploadImageConcurrentQueue; } - (void)multipleOperationDemo { //併發下載多張圖片,而後對全部的圖片完成後。好處在於能夠對更多的操做 NSArray *imageURLs = @[ @"http://zbimg.25pp.com/images/artwork/102/951610982_54x54.jpg", @"http://zbimg.25pp.com/images/artwork/92/855031900_54x54.jpg", @"http://zbimg.25pp.com/images/artwork/246/950137846_54x54.jpg" ]; dispatch_async(self.uploadImageConcurrentQueue, ^{ // 建立信號量 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); // 建立全局並行 for (NSString *url in imageURLs) { NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]]; NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error) { NSLog(@"deal with data here url == %@", url); dispatch_semaphore_signal(semaphore); }]; [task resume]; } NSLog(@"image 2 %@", [NSThread currentThread]); for (int i = 0; i < imageURLs.count; i++) { dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); } NSLog(@"image 3 %@", [NSThread currentThread]); }); }
2016-11-12 18:29:10.234 MutipleThreadPractice[4897:4101983] image 2 <NSThread: 0x7fa6e1f2c4b0>{number = 2, name = (null)} 2016-11-12 18:29:10.337 MutipleThreadPractice[4897:4101987] deal with data here url == http://zbimg.25pp.com/images/artwork/246/950137846_54x54.jpg 2016-11-12 18:29:10.358 MutipleThreadPractice[4897:4101987] deal with data here url == http://zbimg.25pp.com/images/artwork/102/951610982_54x54.jpg 2016-11-12 18:29:10.358 MutipleThreadPractice[4897:4101987] deal with data here url == http://zbimg.25pp.com/images/artwork/92/855031900_54x54.jpg 2016-11-12 18:29:10.358 MutipleThreadPractice[4897:4101983] image 3 <NSThread: 0x7fa6e1f2c4b0>{number = 2, name = (null)}
參考資料
http://www.jianshu.com/p/943dcb9ad632
https://developer.apple.com/reference/dispatch?language=objc
iOS-圖文表並茂,手把手教你GCD
http://www.cocoachina.com/ios/20161031/17887.html
淺談GCD中的信號量
http://www.jianshu.com/p/04ca5470f212