1.GCD學(xué)習(xí)之路

GCD(Grand Central Dispatch)


1. 什么是GCD

GCD實現(xiàn)了異步執(zhí)行任務(wù)。開發(fā)者只需將自己定義的任務(wù)追加到合適的派發(fā)隊列(Dispatch Queue)中,GCD就能生成必要的線程執(zhí)行自定義的任務(wù)。

2. 派發(fā)隊列(Dispatch Queue)

派發(fā)隊列是執(zhí)行任務(wù)的等待隊列,按照追加任務(wù)的順序(先進先出)執(zhí)行任務(wù)。
GCD中的派發(fā)隊列分為兩種,一種是等待正在執(zhí)行的任務(wù)的串行派發(fā)隊列(Serial Dispatch Queue),另一種是不等待正在執(zhí)行中的任務(wù)的并行派發(fā)隊列(Concurrent Dispatch Queue)。

串行隊列(Serial Dispatch Queue)

  • 隊列中的任務(wù)會等待正在執(zhí)行的任務(wù)執(zhí)行結(jié)束,有序執(zhí)行(排隊執(zhí)行)
  • 一個串行隊列只生成并使用一個線程,只能執(zhí)行向它追加的任務(wù)
  • 如果生成了多個串行隊列,這些串行隊列將并發(fā)執(zhí)行
  • 在多個線程要更新相同的資源,導(dǎo)致的數(shù)據(jù)競爭時,使用串行隊列
  • Dispatch Queue系統(tǒng)中為我們提供的串行隊列是Main Dispatch Queue,即在主線程中執(zhí)行的派發(fā)隊列。追加到Main Dispatch Queue的任務(wù)都是在主線程的RunLoop中執(zhí)行,例如用戶界面的更新操作。
//創(chuàng)建一個串行隊列
dispatch_queue_t myQueue = dispatch_queue_create("com.example.gcd", NULL);
// 獲得主線程隊列
dispatch_queue_t mainQueue = dispatch_get_main_queue();
并發(fā)隊列(Concurrent Dispatch Queue)

  • 不用等待正在執(zhí)行的任務(wù)處理結(jié)束,可以并發(fā)執(zhí)行多個任務(wù),此時并發(fā)執(zhí)行的任務(wù)數(shù)量取決于當(dāng)前系統(tǒng)的狀態(tài)。
  • 并發(fā)隊列中的任務(wù)不能產(chǎn)生數(shù)據(jù)競爭問題
  • Dispatch Queue系統(tǒng)中為我們提供的并發(fā)隊列Global Dispatch Queue ,是所有應(yīng)用程序都能使用的并發(fā)隊列,需要在程序中使用并發(fā)隊列只需將獲得Global Dispatch Queue。
  • Global Dispatch Queue有四個優(yōu)先級,分別為高優(yōu)先級(High Priority)、默認優(yōu)先級(Default Priority)、低優(yōu)先級(Low Priority)和后臺優(yōu)先級(Background Priority)。需要注意的是,在向Global Dispatch Queue中追加任務(wù)時,應(yīng)選擇與任務(wù)的優(yōu)先級相同的Global Dispatch Queue。但是用于Global Dispatch Queue的線程并不保證實時性,其執(zhí)行的優(yōu)先級只是大致的判斷。
//創(chuàng)建一個并行隊列
dispatch_queue_t myQueue = dispatch_queue_create("com.example.gcd", DISPATCH_QUEUE_CONCURRENT);
// 獲得默認優(yōu)先級的全局隊列
dispatch_queue_t myQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
3. GCD中常見API

為了防止我說的不準確,下面列舉了一些我認為重要的官方的API

  • dispatch_set_target_Queue 變更生成的Dispatch Queue的優(yōu)先級
void dispatch_set_target_queue(dispatch_object_t object, dispatch_queue_t queue);
  • dispatch_after 并不在指定的時間后執(zhí)行,而是在指定時間后,追加任務(wù)到派發(fā)隊列中去。
void dispatch_after(dispatch_time_t when, dispatch_queue_t queue, dispatch_block_t block);
  • Dispatch Group
    GCD中的特性,能夠?qū)㈥犃兄械娜蝿?wù)分組;
    在等待的派發(fā)隊列中的任務(wù)執(zhí)行完畢后,追加新任務(wù)到派發(fā)隊列中。
    此時可以使用:
  • dispatch_group_notify函數(shù)等待分組中的任務(wù)執(zhí)行完畢,再追加新任務(wù)到指定隊列中。
void dispatch_group_notify(
             dispatch_group_t group, // The dispatch group to observe.
             dispatch_queue_t queue, // The queue to which the supplied block will be submitted when the group completes.
             dispatch_block_t block  // The block to submit when the group completes.
);
  • dispatch_group_wait函數(shù),等待分組中的任務(wù)執(zhí)行結(jié)束,當(dāng)其返回值為0時,表示分組中的任務(wù)執(zhí)行完畢。
/*
* Returns zero on success (all blocks associated with the group completed
* within the specified timeout) or non-zero on error (i.e. timed out).
*/
long dispatch_group_wait(
      dispatch_group_t group,
      dispatch_time_t timeout //  When to timeout (see dispatch_time). As a convenience, there are the DISPATCH_TIME_NOW and DISPATCH_TIME_FOREVER constants.
);
  • dispatch_barrier_async 柵欄
    柵欄必須單獨執(zhí)行,不能與其他任務(wù)并發(fā)執(zhí)行,因此,柵欄只對并發(fā)隊列有意義。
    柵欄只有等待當(dāng)前隊列所有并發(fā)任務(wù)都執(zhí)行完畢后,才會單獨執(zhí)行,待其執(zhí)行完畢,再按照正常的方式繼續(xù)向下執(zhí)行。

執(zhí)行過程
(1)等待追加到并發(fā)隊列上的任務(wù)全部執(zhí)行完
(2)再將dispatch_barrier_async中指定的處理任務(wù)追加到該并發(fā)隊列中
(3)等待dispatch_barrier_async中追加的任務(wù)處理完畢后
(4)并發(fā)隊列恢復(fù)正常操作

可以提高訪問數(shù)據(jù)庫和文件的效率和安全性

/*
 * block as a barrier (relevant only on DISPATCH_QUEUE_CONCURRENT queues).
 */
void dispatch_barrier_async(
dispatch_queue_t queue,  // The target dispatch queue to which the block is submitted.The system will hold a reference on the target queue until the block has finished.
dispatch_block_t block // The block to submit to the target dispatch queue. This function performs Block_copy() and Block_release() on behalf of callers.
);
  • dispatch_apply 按照指定的次數(shù)將指定的塊追加到指定的派發(fā)隊列中,并等待全部任務(wù)執(zhí)行結(jié)束
/*
 * Each invocation of the block will be passed the current index of iteration.
 */
void dispatch_apply(
size_t iterations, // The number of iterations to perform.
dispatch_queue_t queue, // The target dispatch queue to which the block is submitted.s
void (^block)(size_t) // The block to be invoked the specified number of iterations. The result of passing NULL in this parameter is undefined.
);
  • dispatch_suspend/dispatch_resume 掛起/恢復(fù)
    對已經(jīng)執(zhí)行的任務(wù)并沒有作用,線程掛起后,派發(fā)隊列中從第一個未開始執(zhí)行的任務(wù)開始暫停執(zhí)行,線程恢復(fù)后,再由停止的地方重新開始執(zhí)行。

  • 單例的實現(xiàn)
    (1)同步塊 @synchronization
    會出現(xiàn)的問題:所有同步塊會彼此搶奪同一把鎖
    (2)dispatch_once 可以執(zhí)行只需要運行一次的安全代碼,是線程安全,高效的。

/*
 * A predicate for use with dispatch_once(). It must be initialized to zero.
 * Note: static and global variables default to zero.
 */
typedef long dispatch_once_t;
void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);
4. 同步任務(wù)與異步任務(wù)
  • 主要影響:能不能開啟新的線程
  • 同步:只是在當(dāng)前線程中執(zhí)行任務(wù),不具有開啟新線程的能力。

dispatch_sync 同步執(zhí)行,等待任務(wù)處理結(jié)束

  • 異步:可以在新線程中執(zhí)行任務(wù),具有開啟新線程的能力。

dispatch_async 異步執(zhí)行,不等待任務(wù)處理結(jié)束

5. 并行隊列和串行隊列
  • 主要影響:任務(wù)的執(zhí)行方式
  • 并發(fā):允許多個任務(wù)并發(fā)(同時)執(zhí)行。
  • 串行:一個任務(wù)執(zhí)行完畢后,再執(zhí)行下一個任務(wù)。
6. 對比
并行隊列 串行隊列
同步任務(wù) 不需要創(chuàng)建線程 不需要新建線程
異步任務(wù) 有多少個任務(wù),就開N個線程執(zhí)行 需要一個子線程(無需關(guān)心線程的創(chuàng)建和回收)
7. GCD與NSOperationQueue的對比
  • NSOperationQueue的底層實現(xiàn)都是用GCD實現(xiàn)的,它是對GCD的進一步的封裝。接下來就對比一下GCD與NSOperationQueue的功能:
  • GCD的實現(xiàn)是由底層的C語言編寫,在隊列中執(zhí)行的任務(wù)都是塊代碼;而NSOperationQueue及相關(guān)類提供的對象都是OC的對象,NSOperation的對象提供了更多的操作。
  • NSOperationQueue中可以隨時取消已經(jīng)設(shè)定即將要執(zhí)行,但尚未執(zhí)行的任務(wù)(已經(jīng)開始執(zhí)行的任務(wù)是無法停止執(zhí)行的)。而在GCD中并不是不能實現(xiàn)同樣的功能,而是并不像NSOperationQueue的操作那么簡單而已。
  • NSOperation可以設(shè)置任務(wù)間的依賴關(guān)系,舉個簡單的例子:任務(wù)QA依賴任務(wù)QB,即使這兩個任務(wù)在同一個隊列中,前者等待后者執(zhí)行完后再執(zhí)行。
  • NSOperation可以應(yīng)用KVO,監(jiān)聽任務(wù)是否完成/取消的狀態(tài)。
  • 可以在NSOperation的對象中,設(shè)置任務(wù)的優(yōu)先級,可以使同一個并發(fā)隊列中的任務(wù)區(qū)分先后順序地執(zhí)行。而GCD中可以區(qū)分隊列間的先后順序,要區(qū)分隊列中任務(wù)的優(yōu)先級需要大量的代碼才能實現(xiàn)。
  • NSOperation具有繼承性
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 我們知道在iOS開發(fā)中,一共有四種多線程技術(shù):pthread,NSThread,GCD,NSOperation: ...
    請叫我周小帥閱讀 1,554評論 0 1
  • 簡介 GCD(Grand Central Dispatch)是在macOS10.6提出來的,后來在iOS4.0被引...
    sunmumu1222閱讀 953評論 0 2
  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,388評論 21 42
  • 目錄(GCD): 關(guān)鍵詞 混淆點 場景應(yīng)用 總結(jié) 1. 關(guān)鍵詞 線程概念: 獨立執(zhí)行的代碼段,一個線程同時間只能執(zhí)...
    Ryan___閱讀 1,365評論 0 3
  • 《一念紅塵》 目錄 隔了一日,便是那翼界十年一度的百禽節(jié)。本來想邀墨淵一起看個熱鬧,不想他果真是個無趣至極的神仙,...
    翼如閱讀 1,525評論 1 8

友情鏈接更多精彩內(nèi)容