前天學了IOS的NSOperation基本使用,咱們得知NSOperation也是基於IOS GCD(Grand Central Dispatch)實現,其實在作IOS開發中GCD已經基本上可以知足大部分需求。做爲IOS開發工程師頗有必要對GCD作個全面瞭解,今天一邊寫demo一邊對比總結一下GCD使用。併發
GCD是Grand Central Dispatch的簡稱,它是基於C語言的。若是使用GCD,徹底由系統管理線程,咱們不須要編寫線程代碼。只需定義想要執行的任務,而後添加到適當的調度隊列(dispatch queue)。GCD會負責建立線程和調度你的任務,系統直接提供線程管理。app
使用線程就離不開線程隊列的執行方式和任務的執行方式,大體分如下幾個:異步
串行(Serial):讓任務一個接着一個地執行(一個任務執行完畢後,再執行下一個任務)async
並行(Concurrent):可讓多個任務併發(同時)執行(自動開啓多個線程同時執行任務)併發功能只有在異步(dispatch_async)函數下才有效。函數
同步(Synchronous):在當前線程中執行任務,不具有開啓新線程的能力spa
異步(Asynchronous):在新的線程中執行任務,具有開啓新線程的能力線程
上面瞭解到Dispatch 經過分發開發者提供的不一樣queue來調度任務,咱們來看下GCD有哪些隊列。3d
隊列類型 | 建立方式 |
主線程串行隊列(mian)code |
dispatch_get_main_queue();blog |
自定義串行隊列(Serial) | dispatch_queue_create("MySerialQueue", DISPATCH_QUEUE_SERIAL); |
自定義並行隊列(Concurrent) |
dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT); |
全局並行隊列(global) |
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); |
添加執行任務的方式大體有兩種:dispatch_sync 同步執行任務函數,不會開啓新的線程,dispatch_async 異步執行任務函數,會開啓新的線程,接下來分別看下他們的使用示例;
dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_async(mainQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(mainQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(mainQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); });
注意:
主線程串行隊列執行在主線程中,通常使用都是調用dispatch_async添加任務,使用dispatch_sync添加任務會致使死鎖問題。
運行結果:
經過運行結果能夠得知,雖然任務是經過dispatch_async添加執行的,可是並無建立子線程去執行任務,而是執行在主線程中。
有時咱們須要建立一個串行任務而且須要執行在子線程中,這時就須要建立串行隊列,進行異步添加調用方式執行任務。
dispatch_queue_t mySerialQueue = dispatch_queue_create("MySerialQueue", DISPATCH_QUEUE_SERIAL); dispatch_async(mySerialQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(mySerialQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(mySerialQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); });
運行結果:
能夠看出串行隊列異步執行建立了一個線程,而且是依次執行。
相對與串行任務隊列,有時咱們須要同時執行多個任務,這個時候咱們就須要使用並行任務隊列了,這裏咱們採用所有並行隊列。
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(globalQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(globalQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(globalQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); });
這裏能夠根據不一樣的優先級建立不一樣的所有任務隊列
DISPATCH_QUEUE_PRIORITY_HIGH //高優先級
DISPATCH_QUEUE_PRIORITY_DEFAULT //默認優先級
DISPATCH_QUEUE_PRIORITY_LOW //低優先級
DISPATCH_QUEUE_PRIORITY_BACKGROUND //後臺執行
運行結果:
三個任務幾乎是同時進行的,並且動態爲每一個任務開闢了一個線程用於執行任務。並行隊列儘可能使用異步添加任務的方式調用,同步添加任務方式調用不會建立子線程而是任務所有同時執行在主線程中致使UI卡死。
dispatch_queue_t myConcurrentQueue = dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(myConcurrentQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(myConcurrentQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(myConcurrentQueue, ^{ //在block裏寫要執行的任務(代碼) NSLog(@"currentThread3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); });
運行結果和所有並行隊列相似。
有時不管咱們串行執行多任務仍是並行執行多任務,須要這個任務組所有執行完畢以後通知咱們,這裏就須要用到隊列組了。
dispatch_group_t group = dispatch_group_create(); dispatch_queue_t myConcurrentQueue = dispatch_queue_create("MyConcurrentQueue", DISPATCH_QUEUE_CONCURRENT); //dispatch_group_async用於把不一樣的任務歸爲一組 //dispatch_group_notify當指定組的任務執行完畢以後,執行給定的任務 dispatch_group_async(group, myConcurrentQueue, ^{ NSLog(@"currentThread-1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_group_async(group, myConcurrentQueue, ^{ NSLog(@"currentThread-2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_group_async(group, myConcurrentQueue, ^{ NSLog(@"currentThread-3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_group_notify(group, myConcurrentQueue, ^{ NSLog(@"currentThread-g:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); });
運行結果:
既然是多任務執行,就難以免會出現多任務同時訪問同一數據的問題,就會遇到同步的問題,串行隊列不太會碰見數據同步的問題,可是並行隊列必定會有數據同步的問題,IOS GCD考慮的很全面經過調用dispatch_barrier_async函數添加任務來隔離其餘的任務,起到一個柵欄的做用,它等待全部位於barrier函數以前的操做執行完畢後執行,而且在barrier函數執行以後,barrier函數以後的操做纔會獲得執行,該函數須要同dispatch_queue_create函數生成的concurrent Dispatch Queue隊列一塊兒使用。
dispatch_queue_t conCurrentQueue = dispatch_queue_create("myConCurrentQueue", DISPATCH_QUEUE_CONCURRENT); dispatch_async(conCurrentQueue, ^{ NSLog(@"currentThread-1:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(conCurrentQueue, ^{ NSLog(@"currentThread-2:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_barrier_async(conCurrentQueue, ^{ [NSThread sleepForTimeInterval:1.0]; NSLog(@"currentThread-b:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); [NSThread sleepForTimeInterval:1.0]; }); dispatch_async(conCurrentQueue, ^{ NSLog(@"currentThread-3:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); }); dispatch_async(conCurrentQueue, ^{ NSLog(@"currentThread-4:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); });
運行結果:
dispatch_once保證在app運行期間,block中的代碼只執行一次
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ NSLog(@"只執行一次"); //這個block裏的代碼,在程序執行過程當中只會執行一次。 //好比在這裏些單例的初始化 // static YourClass *instance = nil; // instance = [[YourClass alloc] init]; });
dispatch_after延時添加到隊列
double delayInSeconds = 3.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ //dispatch_after函數是延遲執行某個任務,任務既能夠在mainQueue中進行也能夠在其餘queue中進行.既能夠在serial隊列裏執行也能夠在concurrent隊列裏執行。 NSLog(@"currentThread:%@ isMainThread:%@",[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); });
dispatch_apply把一項任務提交到隊列中屢次執行,具體是並行執行仍是串行執行由隊列自己決定
NSArray *array = [NSArray arrayWithObjects:@"who",@"is",@"lcj", nil]; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_apply([array count], queue, ^(size_t index) { NSLog(@"%@ : currentThread:%@ isMainThread:%@",[array objectAtIndex:index],[NSThread currentThread],[[NSThread currentThread] isMainThread]?@"YES":@"NO"); });
用了GCD以後更見佩服Apple公司了,封裝的sdk 真是太完善了。簡單的總結了如何使用GCD,但願在之後的使用中有個大體瞭解。