細說GCD

GCD是多線程編程中很常用的技術(shù),同時,作為一項重要的知識點,在面試中也是“常來之客”,本文通過API進行GCD的歸納和總結(jié)


GCD之前

在蘋果引入GCD技術(shù)之前,Cocoa框架中的NSObject類提供了performSelectorInBackground:withObjectperformSelectorOnMainThread等來實現(xiàn)多線程編程,此外還有NSThread、NSOperation等,伴隨GCD的誕生,NSOperation也進行重寫,基于GCD實現(xiàn)

關(guān)于多線程編程

一個CPU一次只能執(zhí)行一個命令,這樣連續(xù)執(zhí)行命令,相當于一條無分叉的路徑,這樣的路徑就是“線程”。OS和iOS的核心XNU內(nèi)核在進行操作系統(tǒng)事件處理的時候,會切換執(zhí)行路徑。每條執(zhí)行路徑的狀態(tài),會保存到每條路徑專用的內(nèi)存塊中,便于下次執(zhí)行時復(fù)原信息。這種來回切換的操作可以被稱為“上下文切換”,也正是這種切換產(chǎn)生了多線程。

多線程需要注意的問題

  • 數(shù)據(jù)不一致:例如,兩個線程同時更新一個數(shù)據(jù)
  • 死鎖:兩個線程互相等待對方執(zhí)行結(jié)束
  • 內(nèi)存消耗:線程過多會消耗大量內(nèi)存
    ...

GCD的API

dispatch_queue_t

分為兩種

  • Serial Dispatch Queue:串行隊列
    • 系統(tǒng)提供的dispatch_get_main_queue
    • 自定義創(chuàng)建dispatch_queue_create("name", DISPATCH_QUEUE_SERIAL)其中的name是該queue的名字
  • Concurrent Dispatch Queue:并行隊列
    • 系統(tǒng)提供的dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)其中第一個參數(shù)有四種,對應(yīng)不同優(yōu)先級
      • DISPATCH_QUEUE_PRIORITY_BACKGROUND
      • DISPATCH_QUEUE_PRIORITY_LOW
      • DISPATCH_QUEUE_PRIORITY_DEFAULT
      • DISPATCH_QUEUE_PRIORITY_HIGH
    • 自定義創(chuàng)建dispatch_queue_create("name",DISPATCH_QUEUE_CONCURRENT)

dispatch_set_target_queue

  • dispatch_queue_create生成的dispatch_queue_t的優(yōu)先級都是默認優(yōu)先級,如果想要改變優(yōu)先級可以使用:
dispatch_queue_t queue1 = dispatch_queue_create("name", DISPATCH_QUQUE_SERIAL);
dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND);
dispatch_set_target_queue(queue1, queue2);
  • 同時如果將多個串行隊列的目標制定為同一個串行隊列,那么本應(yīng)該并行執(zhí)行的各個串行隊列只能串行地進行執(zhí)行

dispatch_after

在指定時間之后執(zhí)行處理,本質(zhì)上是在指定時間之后將任務(wù)追加到隊列中

dispatch_group_t

隊列組可以用來實現(xiàn):當所有處理結(jié)束之后,執(zhí)行一個操作。正常來說使用串行隊列是很容易實現(xiàn)的,但是如果是并行隊列的話,想要實現(xiàn)這個操作,就需要借助隊列組來實現(xiàn)

dispatch_group_notify

  • 用于group中所有任務(wù)執(zhí)行完之后追加一個操作執(zhí)行
  • 該方法不會阻塞當前線程

dispatch_group_wait

long result = dispatch_group_wait(group, time);
  • 該函數(shù)會阻塞當前線程(即代碼所處的線程)
  • time的選擇
    • 可以是一個固定的時間,如果超時了,該函數(shù)就會返回
    • 也可以是DISPATCH_TIME_FOREVER,表示一直等待,直到group中所有操作執(zhí)行完畢,函數(shù)才返回。
  • 返回值
    • 0:代表group中的任務(wù)全部執(zhí)行完了
    • 非0:代表超時了

dispatch_barrier_async

一般來說,關(guān)于數(shù)據(jù)庫的操作,使用串行隊列能夠避免數(shù)據(jù)異常的問題。但是實際上,讀取操作之間是沒有影響的,為了提高效率,讀取操作通過是并行的,只需要保證寫操作的時候,沒有任何一個讀取操作在進行即可。

dispatch_async(queue, block_reading1);
dispatch_async(queue, block_reading2);
dispatch_barrier_async(queue, block_writing);
dispatch_async(queue, block_reading3);
dispatch_async(queue, block_reading4);

以上代碼中的寫操作,會等待上面代碼中的讀操作(已經(jīng)被添加到隊列中的任務(wù))執(zhí)行完畢之后,開始執(zhí)行,此時,寫操作以下的代碼中的讀操作需要的等待寫操作執(zhí)行完之后才能添加到隊列中執(zhí)行

dispatch_async和dispatch_sync

  • dispatch_async是異步執(zhí)行,代表不會阻塞當前線程,會另外開辟線程執(zhí)行任務(wù)
  • dispatch_sync是同步執(zhí)行,代表會阻塞當前線程,會在當前線程執(zhí)行任務(wù)

dispatch_apply

該函數(shù)可以將block中的任務(wù)指定次數(shù)加入到隊列中,并且會阻塞當前線程,直到所有的任務(wù)全部執(zhí)行完

dispatch_suspend和dispatch_resume

  • dispatch_suspend:掛起后,添加到隊列中的任務(wù),尚未執(zhí)行的處理都會停止執(zhí)行
  • dispatch_resume:將會恢復(fù)以上操作

dispatch_semaphore_t

GCD中的信號量,用于控制并行執(zhí)行,在GCD中,控制并行可以通串行隊列和dispatch_barrier_async來做,而信號量semaphore可以更加精確地控制并行

  • dispatch_semaphore_create(number ):number為信號量的初始量
  • dispatch_semaphore_wait(semaphore, time)
    • 其中time和group中是一樣的
    • 返回值:
      • 0:如果信號量大于等于1,返回0,同時將信息號量減去1
      • 非0:超過指定時間(同時這時信號量為0)
  • dispatch_semaphore_signal(semaphore):將信號量+1

dispatch_once

用于單例處理,相關(guān)代碼只會執(zhí)行一次(即使在多核情況下,也是安全的)

最后編輯于
?著作權(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)容

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