dispatch_async與dispatch_sync區(qū)別

概述

首先明確幾個概念

  • 隊列:隊列分為串行和并行。串行隊列按照A、B、C、D的順序添加四個任務(wù),這四個任務(wù)按照順序執(zhí)行,結(jié)束順序也肯定是A、B、C、D,而并行隊列同時執(zhí)行這四個任務(wù),完成的順序因此也是隨機的。
  • 異步執(zhí)行(async)和同步執(zhí)行(sync):使用dispatch_async調(diào)用一個block,這個block會被放到指定的queue_1隊列尾等待執(zhí)行,至于這個block是被并行還是串行執(zhí)行,只和dispatch_async中的指定的queue_1有關(guān),但是dispatch_async會馬上返回。使用dispatch_sync同樣也是把block放到指定的queue_2上執(zhí)行,但是會等待這個block執(zhí)行完畢后才返回,這期間會阻塞當前運行調(diào)用dispatch_async或dispatch_sync代碼的queue(通常為main_queue)直到sync函數(shù)返回。

以打電話給查號臺為例:

  • 同步:打電話給查號臺,問某個地方的電話號碼,接線員會告訴你稍等,然后為你查號,此時你的電話沒有掛斷,其他的電話也不能打進來,等到接線員查找到了你要找的電話號,告訴你后,才將電話掛斷
  • 異步:打電話給查號臺,問某個地方的電話號碼,接線員知道了你的請求后,會立刻掛斷電話,此時其他的電話可以打進來。然后開始為你查號。等到查找到了你要找的電話號,會再打電話通知你。

示例

異步
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"async:1");
    });
NSLog(@"async:2");
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"async:3");
    });
NSLog(@"async:4");

結(jié)果為

async:2
async:4
async:1
async:3

可以看出,dispatch_async將block追加到線程中后,并未等待,立刻執(zhí)行后面的代碼

同步
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"sync:1");
    });
NSLog(@"sync:2");
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"sync:3");
    });
NSLog(@"sync:4");

結(jié)果為

sync:1
sync:2
sync:3
sync:4

可以看出,dispatch_sync將block追加到線程中后,等待block執(zhí)行完畢后才接著執(zhí)行后面的代碼

死鎖

// 前提條件:當前的 queue 為 main_queue
dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"mainQueue_sync:1");
});

上述代碼會造成死鎖。原因:前提條件是當前 queue 為 main_queue。main_queue 為串行隊列,在當前 queue 上調(diào)用 sync 函數(shù)。需要執(zhí)行的 block 被放到當前 queue 的隊尾等待被執(zhí)行,因為這是一個串行的 queue,調(diào)用 sync 函數(shù)會阻塞當前隊列,等待 block 被執(zhí)行->這個 block 一直不會被執(zhí)行-> sync 函數(shù)一直不返回,所以當前 queue 就被阻塞了,造成了死鎖。
一般串行隊列中 sync 到自身上會產(chǎn)生死鎖,sync 到其他隊列上一般不會產(chǎn)生死鎖,如在自定義 queue 中 sync main_queue,等到 main_queue 執(zhí)行完畢再繼續(xù)執(zhí)行操作。
說明

開發(fā)者要做的只是定義想執(zhí)行的任務(wù)并追加到適當?shù)腄ispatch Queue中。

上述引用自蘋果官方對GCD的說明,因此Dispatch_async和Dispatch_sync的作用是將block追加到隊列中。這句話對于上述理解死鎖有很大幫助。

實例

print(1)
serialQueue.async {
    print(2)
    serialQueue.sync {
        print(3)
}
print(4)
}
print(5)

分析:只會打印1、5、2,然后就死鎖了。原因是列serialQueue.async的block1被異步追加到串行隊列上后,開始執(zhí)行,這個block1中又被同步追加了一個block2,此時serialQueue被阻塞,等待block2執(zhí)行完畢,但是block1還未執(zhí)行完畢,由于是串行隊列,block只能按照追加的先后順序一個一個執(zhí)行:線程被阻塞->block1停止執(zhí)行->block2等block1執(zhí)行完畢->因此就造成了死鎖。

注意

dispatch_sync 官方文檔

As an optimization, dispatch_sync() invokes the block on the current thread when possible.
作為優(yōu)化,如果可能,直接在當前線程調(diào)用這個block。

通過dispatch_sync添加的任務(wù),在哪個線程添加就會在哪個線程執(zhí)行。因此向并發(fā)隊列添加的任務(wù),沒有開啟新線程,而是在主線程執(zhí)行的

參考

  1. GCD有關(guān)問題:dispatch_sync(dispatch_get_main_queue(), ^{NSLog(@"Hello ?");}); 死鎖的原因
  2. Objective-C高級編程 P161 dispatch_sync
最后編輯于
?著作權(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)容