日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

对GCD的一些理解和实践

發布時間:2023/12/10 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 对GCD的一些理解和实践 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
對GCD的一些理解和實踐

GCD

  GCD,全程Grand Central Dispatch,是蘋果為了多核并行提出的解決方案。它是使用C語言實現,但是由于用了block來處理回調,所以使用起來十分方便。并且GCD會自動管理線程的生命周期,不需要我們去管理。

任務和隊列

  GCD中有兩個重要的概念,任務和隊列。

  1、任務,就是我們想要處理的事情,任務可以分為同步執行和異步執行:

  同步(sync):使用dispatch_sync(dispatch_queue_t queue, dispatch_block_t block)?創建,同步執行任務時會阻塞當前線程等待block執行完畢返回。然后當前線程才會繼續執行下去。

  異步(async):使用dispatch_async(dispatch_queue_t queue, dispatch_block_t block)創建,異步任務不會阻塞當前線程,任務創建后立即返回線程往下執行。

  2、隊列,存放任務,并將任務由先入先出地派發出去。分為串行隊列和并行隊列:

  串行隊列(Serial queue):隊列中的任務根據創建順序,先入先出地執行,等待上一個任務執行完畢后,才會執行下一個任務,有嚴格的執行先后順序。

  并行隊列(Concurrent queue):隊列會根據先后順序,將任務派發出去,并行執行。所有的任務幾乎都是一起執行的。不過需要注意,GCD 會根據系統資源控制并行的數量,所以如果任務很多,它并不會讓所有任務同時執行。有一個表,可以大體說明任務和隊列之間的配合使用:

?串行隊列并行隊列
同步執行任務當前線程,一個一個執行當前線程,一個一個執行
異步執行任務另開線程,一個一個執行開很多線程,一起執行

  下面是任務和隊列的使用演示:

  

/*** 串行隊列中的任務會等待正在執行的任務執行結束,排隊執行*/dispatch_queue_t serial_queue = dispatch_queue_create("serial.queue", DISPATCH_QUEUE_SERIAL);//主隊列dispatch_queue_t mainQueue = dispatch_get_main_queue();/*** 并行,不等待正在執行的任務的處理結果,可以并發執行多個任務*/dispatch_queue_t concurrent_queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);//全局隊列dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);//在串行隊列中創建幾個同步任務,在主線程順序執行dispatch_sync(serial_queue, ^{NSLog(@"task a ,thread:%@",[NSThread currentThread]);});dispatch_sync(serial_queue, ^{NSLog(@"task b ,thread:%@",[NSThread currentThread]);});dispatch_sync(serial_queue, ^{NSLog(@"task c ,thread:%@",[NSThread currentThread]);});//在串行隊列中創建幾個異步任務,在主線程順序執行dispatch_sync(serial_queue, ^{NSLog(@"task aa ,thread:%@",[NSThread currentThread]);});dispatch_sync(serial_queue, ^{NSLog(@"task bb ,thread:%@",[NSThread currentThread]);});dispatch_sync(serial_queue, ^{NSLog(@"task cc ,thread:%@",[NSThread currentThread]);});//在串行隊列中創建幾個異步任務,另開1個線程順序執行dispatch_async(serial_queue, ^{NSLog(@"task 1 ,thread:%@",[NSThread currentThread]);});dispatch_async(serial_queue, ^{NSLog(@"task 1 ,thread:%@",[NSThread currentThread]);});dispatch_async(serial_queue, ^{NSLog(@"task 1 ,thread:%@",[NSThread currentThread]);});//在并隊列中創建幾個異步任務,另開多個線程同時執行dispatch_async(concurrent_queue, ^{NSLog(@"task 11 ,thread:%@",[NSThread currentThread]);});dispatch_async(concurrent_queue, ^{NSLog(@"task 22 ,thread:%@",[NSThread currentThread]);});dispatch_async(concurrent_queue, ^{NSLog(@"task 33 ,thread:%@",[NSThread currentThread]);});

?

任務組和柵欄

  有時候當我們想要為多個任務添加依賴關系的時候,就可以使用任務組dispatch_group和dispatch_barrier。

  任務組是將若干個任務放在一個group 中,這些任務可以在同一隊列也可以在不同隊列,然后用dispatch_group_notify()和dispatch_group_wait()對任務組中任務的完成進行處理。

1、dispatch_group_notify()中的任務會在group中多有任務執行完畢后執行

dispatch_group_t group = dispatch_group_create();/*** group中所有任務任務執行完畢后,執行dispatch_group_notify中的任務*/dispatch_group_async(group, serial_queue, ^{sleep(2);NSLog(@"serial_queue1");});dispatch_group_async(group, serial_queue, ^{sleep(2);NSLog(@"serial_queue2");});dispatch_group_async(group, concurrent_queue, ^{sleep(2);NSLog(@"concurrent_queue1");});dispatch_group_notify(group, dispatch_get_main_queue(), ^{NSLog(@"return main queue");});

?

2、dispatch_group_wait()中可傳入一個給定時間,如果在等待時間結束前group所有任務執行完畢則返回0,否則返回非0,這個函數是一個同步任務

/*** dispatch_group_wait給定一個時間,如果在等待時間結束前group所有任務執行完畢則返回0,否則返回非0,這個函數是一個同步任務*/dispatch_group_async(group, serial_queue, ^{sleep(3);NSLog(@"serial_queue1");});dispatch_group_async(group, serial_queue, ^{sleep(2);NSLog(@"serial_queue2");});dispatch_group_async(group, concurrent_queue, ^{sleep(3);NSLog(@"concurrent_queue1");});long i = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 6));NSLog(@"-- %ld --",i);dispatch_group_async(group, concurrent_queue, ^{NSLog(@"finish all");});

?

3、可以使用dispatch_group_enter()和dispatch_group_leave()來添加任務組的任務,兩者必須要成對出現,兩個函數之間的代碼便是要加入任務住的任務

/*** 使用dispatch_group_enter和dispatch_group_leave添加組任務,兩者必須要成對出現*/dispatch_group_enter(group);sleep(2);NSLog(@"1");dispatch_group_leave(group);dispatch_group_enter(group);dispatch_async(concurrent_queue, ^{sleep(3);NSLog(@"2");dispatch_group_leave(group);});dispatch_group_enter(group);sleep(2);NSLog(@"3");dispatch_group_leave(group);long i = dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 6));NSLog(@"-- %ld --",i);dispatch_group_async(group, concurrent_queue, ^{NSLog(@"finish all");});

?

  柵欄是將一個隊列中的任務分割成兩部分,在柵欄任務之前添加的任務全部執行完畢后,單獨執行柵欄任務,執行完畢后,再繼續執行后面的任務。柵欄必須單獨執行,不能與其他任務并發執行,因此,柵欄只對并發隊列有意義。柵欄只有等待當前隊列所有并發任務都執行完畢后,才會單獨執行,待其執行完畢,再按照正常的方式繼續向下執行。

dispatch_queue_t concurrent_queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(concurrent_queue, ^{sleep(2);NSLog(@"1");});dispatch_async(concurrent_queue, ^{sleep(2);NSLog(@"2");});dispatch_async(concurrent_queue, ^{sleep(2);NSLog(@"3");});dispatch_barrier_async(concurrent_queue, ^{sleep(2);NSLog(@"barrier");});dispatch_async(concurrent_queue, ^{sleep(2);NSLog(@"finish1");});dispatch_async(concurrent_queue, ^{NSLog(@"finish2");});

?

重復執行dispatchApply 和 單次執行dispatch_once

  dispatch_apply()是將一個任務提交到隊列中重復執行,并行或者串行由隊列決定,dispatch_apply會阻塞當前線程,等到所有任務完成后返回

dispatch_queue_t concurrent_queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);dispatch_apply(5, concurrent_queue, ^(size_t index) {sleep(1);NSLog(@"index:%zu",index);});NSLog(@"finish");

  dispatch_once()確保block內代碼在整個應用運行期間只執行一次

//確保block內代碼在整個應用運行期間只執行一次static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{NSLog(@"just run once in application");});

線程同步、信號量和線程死鎖  

  多線程處理經常需要考慮到資源搶占的問題,比如經典的購票問題,寫數據庫等問題。處理問題的辦法有很多,下面介紹最簡單的兩種做法:加上同步鎖,或者用信號量來解決。

  同步鎖,每當有線程訪問鎖里的資源時,會將此部分鎖住,拒絕其他線程訪問。直到占用的線程推出后才解鎖,允許其他資源訪問。

//同步鎖,對block內的代碼加鎖,同一時間內只允許一個線程訪問@synchronized(self) {NSLog(@"lock");};

  信號量dispatch_semaphore,一開始設置信號的總量,然后用dispatch_semaphore_wait()和dispatch_semaphore_signal()來管理信號量,達到控制線程訪問的目的

//信號量dispatch_semaphoredispatch_group_t group = dispatch_group_create();//設置總信號量dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);for (int i = 0; i<100; i++) {//設置等待信號,如果此時信號量大于0,那么信號量減一并繼續往下執行//如果此時信號量小于0,會一直等待,直到超時//如果超時返回非零,成功執行返回0dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*50));dispatch_group_async(group, concurrent_queue, ^{sleep(1);NSLog(@"%d",i);//發送信號,讓信號量加一dispatch_semaphore_signal(semaphore);});}dispatch_group_notify(group, concurrent_queue, ^{NSLog(@"finish");});

  

  GCD盡管使用起來非常方便,但是如果使用不當也活造成一些麻煩,下面列舉幾個會造成線程死鎖的場合:

//在并行隊列中,在當前隊列調用dispatch_sync,并傳入當前隊列執行,并不會造成deadlock。dispatch_sync會阻塞當前線程,但是由于隊列是并行執行,所以block中的任務會馬上執行后返回。 - (void)syncAndConcurrentQueue {dispatch_queue_t queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);dispatch_sync(queue, ^{NSLog(@"Jump to concurrent.queue! ,thread:%@",[NSThread currentThread]);dispatch_sync(queue, ^{sleep(3);NSLog(@"success6 ,thread:%@",[NSThread currentThread]);});NSLog(@"return");}); }//在串行隊列中,在當前隊列調用dispatch_sync,并傳入當前隊列執行,會造成deadlock。 dispatch_sync會阻塞當前線程,等待block中的任務執行完之后再繼續執行,但是由于隊列是串行執行,block中的任務放在最后,所以永遠沒有機會執行,線程死鎖 - (void)synAndSerialQueue {dispatch_queue_t queue = dispatch_queue_create("serial.queue", DISPATCH_QUEUE_SERIAL);dispatch_async(queue, ^{NSLog(@"Jump to serial.queue!");dispatch_sync(queue, ^{NSLog(@"success");});NSLog(@"return");}); }//任務1會阻塞主線程,直到block中執行完畢返回,任務二在主線程添加了了一個同步任務,阻塞當前線程,知道任務執行完畢返回,而任務2沒有機會被執行。造成兩條線程死鎖。 - (void)recycle {dispatch_queue_t concurrent_queue = dispatch_queue_create("concurrent.queue", DISPATCH_QUEUE_CONCURRENT);//任務1dispatch_sync(concurrent_queue, ^{NSLog(@"jump to concurrent queue");//任務2dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"return main queue");});}); }

?

?

總結

  以上是使用GCD的一些心得,GCD使用起來盡管十分便利,但是在處理一些場景比如取消任務時候會很麻煩,所以實現簡單功能的時候推薦使用GCD,如果功能復雜的話建議使用NSOperation和NSOperationQueue,NSOperationQueue的底層也是由GCD實現的,完全面向對象,所以使用起來更好理解。下次有空講講NSOperation和NSOperationQueue。以上代碼demo地址:https://github.com/GarenChen/GCDDemo

?原本文鏈接:http://www.cnblogs.com/GarenChen/p/5858280.html

轉載于:https://www.cnblogs.com/jx451578429/p/5893373.html

總結

以上是生活随笔為你收集整理的对GCD的一些理解和实践的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。