如何處理多個網絡請求的並發的情況
一、概念
1.並發 當有多個線程在操作時,如果系統只有一個CPU,則它根本不可能真正同時進行一個以上的線程,它只能把CPU運行時間划分成若干個時間段,再將時間 段分配給各個線程執行,在一個時間段的線程代碼運行時,其它線程處於掛起狀。.這種方式我們稱之為並發(Concurrent)。
2.並行 當系統有一個以上CPU時,則線程的操作有可能非並發。當一個CPU執行一個線程時,另一個CPU可以執行另一個線程,兩個線程互不搶占CPU資源,可以同時進行,這種方式我們稱之為並行(Parallel)。
3.區別 並發和並行是即相似又有區別的兩個概念,並行是指兩個或者多個事件在同一時刻發生;而並發是指兩個或多個事件在同一時間間隔內發生。
舉個栗子
1).並發 一個送外賣的A需要把兩份外賣分別送到兩個客戶B和C手里。 A必須先送完B外賣才能接着送C的。這就是並發
2).並行 客戶C 分別從餓了么和美團訂了一共兩份外賣。那么外賣員A和外賣員B需要把外賣一同送到客戶C手里。 這就是並行
在iOS中,經常可以看見有這樣的需求,就是一個方法要等另外一個方法執行完畢再做相對應的處理,比如說一些網絡請求,需要根據上一個請求的返回值做相對應的處理再執行第二個請求,所以我們不能讓兩個請求同時去請求網絡。下面就記錄以下通過GCD和NSOperationQueue來控制並發。
二、代碼部分(GCD)
GCD
1 #import <Foundation/Foundation.h> 2 3 int main(int argc, const char * argv[]) { 4 5 @autoreleasepool { 6 7 // 創建信號量 8 9 __block dispatch_semaphore_t sem = dispatch_semaphore_create(0); 10 11 // 創建隊列 12 13 dispatch_queue_t queue = dispatch_queue_create("testBlock", NULL); 14 15 dispatch_async(queue, ^{ 16 17 for (int i = 0; i<10; i++) { 18 19 NSLog(@"i的值是:%d",i); 20 21 } 22 23 // 發送通知 24 25 dispatch_semaphore_signal(sem); 26 27 }); 28 29 30 31 // 信號量等待 32 33 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 34 35 36 37 for (int j = 0; j<20; j++) { 38 39 NSLog(@"j的值是:%d",j); 40 41 } 42 43 } 44 45 return 0; 46 47 }
打印結果為
2015-07-28 16:17:04.195 多線程[16370:1833932] i的值是:0
2015-07-28 16:17:04.197 多線程[16370:1833932] i的值是:1
2015-07-28 16:17:04.197 多線程[16370:1833932] i的值是:2
2015-07-28 16:17:04.197 多線程[16370:1833932] i的值是:3
2015-07-28 16:17:04.197 多線程[16370:1833932] i的值是:4
2015-07-28 16:17:04.198 多線程[16370:1833932] i的值是:5
2015-07-28 16:17:04.198 多線程[16370:1833932] i的值是:6
2015-07-28 16:17:04.198 多線程[16370:1833932] i的值是:7
2015-07-28 16:17:04.198 多線程[16370:1833932] i的值是:8
2015-07-28 16:17:04.198 多線程[16370:1833932] i的值是:9
2015-07-28 16:17:04.198 多線程[16370:1833932] j的值是:0
2015-07-28 16:17:04.199 多線程[16370:1833932] j的值是:1
2015-07-28 16:17:04.199 多線程[16370:1833932] j的值是:2
2015-07-28 16:17:04.199 多線程[16370:1833932] j的值是:3
2015-07-28 16:17:04.199 多線程[16370:1833932] j的值是:4
2015-07-28 16:17:04.199 多線程[16370:1833932] j的值是:5
2015-07-28 16:17:04.199 多線程[16370:1833932] j的值是:6
2015-07-28 16:17:04.199 多線程[16370:1833932] j的值是:7
2015-07-28 16:17:04.221 多線程[16370:1833932] j的值是:8
2015-07-28 16:17:04.221 多線程[16370:1833932] j的值是:9
2015-07-28 16:17:04.222 多線程[16370:1833932] j的值是:10
2015-07-28 16:17:04.222 多線程[16370:1833932] j的值是:11
2015-07-28 16:17:04.222 多線程[16370:1833932] j的值是:12
2015-07-28 16:17:04.222 多線程[16370:1833932] j的值是:13
2015-07-28 16:17:04.222 多線程[16370:1833932] j的值是:14
2015-07-28 16:17:04.222 多線程[16370:1833932] j的值是:15
2015-07-28 16:17:04.222 多線程[16370:1833932] j的值是:16
2015-07-28 16:17:04.223 多線程[16370:1833932] j的值是:17
2015-07-28 16:17:04.223 多線程[16370:1833932] j的值是:18
2015-07-28 16:17:04.223 多線程[16370:1833932] j的值是:19
我們看到先打印完i值后在打印j值 這就完成了並發請求
NSOperationQueue
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 創建一個隊列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; // 設置最大線程數 queue.maxConcurrentOperationCount = 5; // 創建一個A操作 NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i<10; i++) { NSLog(@"i的值是:%d",i); } }]; // 創建一個B操作 NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{ for (int j = 0; j<20; j++) { NSLog(@"j的值是:%d",j); } }]; // 分別加入到隊列中 [queue addOperation:operationA]; [queue addOperation:operationB]; }
打印結果
2015-07-28 17:51:09.508 111[16598:1880752] j的值是:0
2015-07-28 17:51:09.508 111[16598:1880750] i的值是:0
2015-07-28 17:51:09.509 111[16598:1880752] j的值是:1
2015-07-28 17:51:09.509 111[16598:1880750] i的值是:1
2015-07-28 17:51:09.509 111[16598:1880752] j的值是:2
2015-07-28 17:51:09.509 111[16598:1880750] i的值是:2
2015-07-28 17:51:09.509 111[16598:1880752] j的值是:3
2015-07-28 17:51:09.509 111[16598:1880750] i的值是:3
2015-07-28 17:51:09.509 111[16598:1880752] j的值是:4
2015-07-28 17:51:09.509 111[16598:1880750] i的值是:4
2015-07-28 17:51:09.509 111[16598:1880752] j的值是:5
2015-07-28 17:51:09.509 111[16598:1880750] i的值是:5
2015-07-28 17:51:09.509 111[16598:1880752] j的值是:6
2015-07-28 17:51:09.509 111[16598:1880750] i的值是:6
2015-07-28 17:51:09.509 111[16598:1880752] j的值是:7
2015-07-28 17:51:09.509 111[16598:1880750] i的值是:7
2015-07-28 17:51:09.509 111[16598:1880752] j的值是:8
2015-07-28 17:51:09.509 111[16598:1880750] i的值是:8
2015-07-28 17:51:09.510 111[16598:1880752] j的值是:9
2015-07-28 17:51:09.510 111[16598:1880750] i的值是:9
我們看到打印順序是交替進行的。 那么如何進行順序操作呢。只需一行代碼。
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 創建一個隊列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; // 設置最大線程數 queue.maxConcurrentOperationCount = 5; // 創建一個A操作 NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{ for (int i = 0; i<10; i++) { NSLog(@"i的值是:%d",i); } }]; // 創建一個B操作 NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{ for (int j = 0; j<20; j++) { NSLog(@"j的值是:%d",j); } }]; // 添加依賴 B要在A打印完在進行打印 所以是B依賴於A 那么只需要添加如下代碼即可完成 [operationB addDependency:operationA]; // 分別加入到隊列中 [queue addOperation:operationA]; [queue addOperation:operationB]; }
打印結果
2015-07-28 17:54:02.606 111[16625:1882738] i的值是:0
2015-07-28 17:54:02.609 111[16625:1882738] i的值是:1
2015-07-28 17:54:02.609 111[16625:1882738] i的值是:2
2015-07-28 17:54:02.609 111[16625:1882738] i的值是:3
2015-07-28 17:54:02.609 111[16625:1882738] i的值是:4
2015-07-28 17:54:02.609 111[16625:1882738] i的值是:5
2015-07-28 17:54:02.609 111[16625:1882738] i的值是:6
2015-07-28 17:54:02.609 111[16625:1882738] i的值是:7
2015-07-28 17:54:02.610 111[16625:1882738] i的值是:8
2015-07-28 17:54:02.610 111[16625:1882738] i的值是:9
2015-07-28 17:54:02.610 111[16625:1882738] j的值是:0
2015-07-28 17:54:02.610 111[16625:1882738] j的值是:1
2015-07-28 17:54:02.610 111[16625:1882738] j的值是:2
2015-07-28 17:54:02.610 111[16625:1882738] j的值是:3
2015-07-28 17:54:02.610 111[16625:1882738] j的值是:4
2015-07-28 17:54:02.611 111[16625:1882738] j的值是:5
2015-07-28 17:54:02.611 111[16625:1882738] j的值是:6
2015-07-28 17:54:02.611 111[16625:1882738] j的值是:7
2015-07-28 17:54:02.611 111[16625:1882738] j的值是:8
2015-07-28 17:54:02.611 111[16625:1882738] j的值是:9
順序操作請求完成。