0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

為什么需要并發(fā)編程?GCD如何執(zhí)行并發(fā)/并行?

Android編程精選 ? 來(lái)源:稀土掘金 ? 2023-07-21 10:26 ? 次閱讀

為什么需要并發(fā)

假設(shè)您在主線程上并且需要來(lái)自服務(wù)器的數(shù)據(jù)。您從服務(wù)器請(qǐng)求數(shù)據(jù)并等待,直到您從服務(wù)器獲得響應(yīng)。在此期間,您的主線程不會(huì)執(zhí)行任何與 UI 相關(guān)的工作,這會(huì)使您的應(yīng)用程序無(wú)響應(yīng)。

假設(shè)服務(wù)器在此期間需要 10 秒才能給出響應(yīng),如果用戶(hù)點(diǎn)擊按鈕,系統(tǒng)將不會(huì)響應(yīng)它,這對(duì)用戶(hù)來(lái)說(shuō)非常糟糕。

如果你可以在同一時(shí)間(或大約在同一時(shí)間)運(yùn)行的這兩個(gè)任務(wù),一個(gè)線程專(zhuān)門(mén)處理用戶(hù)界面相關(guān)的工作,其他的線程處理耗時(shí)任務(wù)。這樣一來(lái),上面的情況就不會(huì)發(fā)生了。

并發(fā)

并發(fā)意味值應(yīng)用程序可以使用分割時(shí)間的方式同時(shí)處理多個(gè)任務(wù)。如果一臺(tái)計(jì)算機(jī)只有一個(gè)CPU,那么它無(wú)法在一個(gè)精確的時(shí)間點(diǎn)上同時(shí)運(yùn)行多個(gè)任務(wù),但是可以通過(guò)上下文切換的方式在一段時(shí)間(很短,比如1s)內(nèi)執(zhí)行多個(gè)任務(wù)。

上下文切換是指存儲(chǔ)線程的狀態(tài),并在將來(lái)恢復(fù)這個(gè)狀態(tài)繼續(xù)執(zhí)行。這允許多個(gè)進(jìn)程共享一個(gè)CPU資源,同時(shí)這也是多任務(wù)操作系統(tǒng)的基本功能。

并行

并行指多個(gè)任務(wù)同時(shí)發(fā)生,并沒(méi)有上下文切換。

對(duì)于我們討論的情況,如果并行地執(zhí)行網(wǎng)絡(luò)調(diào)用,那么將有兩個(gè)線程在兩個(gè)不同的內(nèi)核上執(zhí)行主線程和后臺(tái)指令,與前一個(gè)相比,速度非常快,但需要額外的物理要求-需要CPU有多核。

如下圖所示,在并行的情況下,兩條線程真的在同時(shí)執(zhí)行;而并發(fā),在一個(gè)線程執(zhí)行時(shí),另一個(gè)在休眠。

e2981d1e-26f1-11ee-962d-dac502259ad0.jpg

關(guān)于線程的小知識(shí)

在單核CPU上,如果你創(chuàng)建了10條線程,那么它只能使用并發(fā)/時(shí)間片分割/上下文切換的方式執(zhí)行它們

在10核CPU上,如果你創(chuàng)建了10條線程,那么它們可能以下面的方式執(zhí)行:

使用上下文切換的方式在1個(gè)核心上并發(fā)執(zhí)行

每個(gè)線程在獨(dú)立的核心上并行執(zhí)行

一部分并發(fā)執(zhí)行,另外一部分并行執(zhí)行

在單核CPU上,如果你創(chuàng)建了1000條線程,那么CPU只會(huì)忙著上下文切換,而不會(huì)執(zhí)行實(shí)質(zhì)性的任務(wù)??梢?jiàn),創(chuàng)建合理的線程數(shù)量也是一個(gè)不小的挑戰(zhàn)。

GCD 如何執(zhí)行并發(fā)/并行

GCD 在幕后管理共享線程池并在該池中添加最佳線程數(shù)。使用 GCD,您將代碼塊或工作項(xiàng)添加到隊(duì)列中,GCD 決定在哪個(gè)線程上執(zhí)行它們。GCD 根據(jù)系統(tǒng)物理?xiàng)l件或當(dāng)前負(fù)載并發(fā)或并行執(zhí)行此任務(wù)。

注意:如果你給 GCD 分配兩個(gè)任務(wù),你不確定它是并發(fā)還是并行運(yùn)行。

從現(xiàn)在開(kāi)始,我們將使用術(shù)語(yǔ)并發(fā)代表并發(fā)/并行。

使用GCD,開(kāi)發(fā)者有什么責(zé)任

您所要做的就是定義要并發(fā)執(zhí)行的任務(wù)并將它們添加到適當(dāng)?shù)恼{(diào)度隊(duì)列中。GCD 負(fù)責(zé)創(chuàng)建所需的線程并安排您的任務(wù)在這些線程上運(yùn)行,這非???/p>

調(diào)度隊(duì)列

調(diào)度隊(duì)列是一種基于 C 的組件,用于執(zhí)行自定義任務(wù)。調(diào)度隊(duì)列總是按照任務(wù)添加到隊(duì)列的順序出列和啟動(dòng)任務(wù)。調(diào)度隊(duì)列是線程安全的,這意味著您可以同時(shí)從多個(gè)線程訪問(wèn)它們。注意,隊(duì)列不是線程!

如果您想通過(guò) GCD 執(zhí)行并發(fā)任務(wù),請(qǐng)將它們添加到適當(dāng)?shù)恼{(diào)度隊(duì)列中。GCD 將基于隊(duì)列的配置,挑選并執(zhí)行任務(wù)。

串行隊(duì)列

串行調(diào)度隊(duì)列按照添加到隊(duì)列的順序一次執(zhí)行一項(xiàng)任務(wù)。假設(shè)您將五個(gè)任務(wù)添加到串行隊(duì)列, GCD 將從第一個(gè)任務(wù)開(kāi)始,在它執(zhí)行完成之前,第二個(gè)任務(wù)將不會(huì)開(kāi)始。

串行隊(duì)列通常用于同步對(duì)特定資源的訪問(wèn)。假設(shè)您有兩個(gè)網(wǎng)絡(luò)調(diào)用都需要 10 秒,因此您決定將這兩個(gè)任務(wù)移到某些后臺(tái)線程上,而且它們都在訪問(wèn)相同的資源,您想要進(jìn)行一些同步,您可以將這些任務(wù)放在串行隊(duì)列中。

串行隊(duì)列串行執(zhí)行任務(wù)意味著一次只有一個(gè)線程在使用,但不能保證它們?cè)谕痪€程上執(zhí)行。

您可以根據(jù)需要?jiǎng)?chuàng)建任意數(shù)量的串行隊(duì)列,并且每個(gè)隊(duì)列相對(duì)于所有其他隊(duì)列同時(shí)運(yùn)行。換句話說(shuō),如果您創(chuàng)建四個(gè)串行隊(duì)列,則每個(gè)隊(duì)列一次僅執(zhí)行一項(xiàng)任務(wù),但最多仍可以同時(shí)執(zhí)行四個(gè)任務(wù),每個(gè)隊(duì)列一個(gè)。

如果您有兩個(gè)任務(wù)訪問(wèn)相同的共享資源,但他們?cè)诓煌木€程上運(yùn)行,則任一線程都可以先修改資源,您需要使用鎖來(lái)確保兩個(gè)任務(wù)不會(huì)同時(shí)修改該資源。您可以將兩個(gè)任務(wù)添加到串行調(diào)度隊(duì)列,以確保在任何給定時(shí)間只有一個(gè)任務(wù)修改共享資源。這種基于隊(duì)列的同步比鎖更有效,因?yàn)樵谟懈?jìng)爭(zhēng)和無(wú)競(jìng)爭(zhēng)的情況下,鎖總是需要一個(gè)昂貴的內(nèi)核陷阱,而調(diào)度隊(duì)列主要在應(yīng)用程序的進(jìn)程空間中工作,并且只在絕對(duì)必要時(shí)調(diào)用內(nèi)核。

并發(fā)隊(duì)列

并發(fā)隊(duì)列并發(fā)執(zhí)行一個(gè)或多個(gè)任務(wù)

如果您將四個(gè)單獨(dú)的任務(wù)添加到并發(fā)隊(duì)列,這些任務(wù)將按照它們添加到隊(duì)列的順序啟動(dòng)。GCD 選擇第一個(gè)任務(wù)在一段時(shí)間內(nèi)執(zhí)行它,然后在不等待第一個(gè)任務(wù)完成的情況下啟動(dòng)第二個(gè)任務(wù),依此類(lèi)推。這是理想的地方,這不僅可以真正地做到后臺(tái)執(zhí)行,而且不關(guān)心這些任務(wù)是否也與其他任務(wù)同時(shí)運(yùn)行

當(dāng)前正在執(zhí)行的任務(wù)在由調(diào)度隊(duì)列管理的不同線程上運(yùn)行。

在任何時(shí)間點(diǎn),執(zhí)行的任務(wù)數(shù)量是可變的,這取決于系統(tǒng)條件。當(dāng)您創(chuàng)建具有四個(gè)任務(wù)的并發(fā)隊(duì)列時(shí),它會(huì)創(chuàng)建多少個(gè)線程?答案是不確定。GCD 將使用多少個(gè)線程來(lái)執(zhí)行這些任務(wù),這取決于系統(tǒng)條件,它有可能可以使用一條或四條線程。

在 GCD 中,有兩種方法可以同時(shí)運(yùn)行任務(wù),創(chuàng)建自定義并發(fā)隊(duì)列或使用全局并發(fā)隊(duì)列。

自定義和全局并發(fā)隊(duì)列的區(qū)別

如下圖所示,我們創(chuàng)建了兩個(gè)全局并發(fā)隊(duì)列,您可以看到由于全局隊(duì)列是整個(gè)系統(tǒng)共享的并發(fā)隊(duì)列,因此它始終返回相同的隊(duì)列;而自定義并發(fā)隊(duì)列是私有的,每次創(chuàng)建時(shí)都會(huì)返回新隊(duì)列。

e2bde26a-26f1-11ee-962d-dac502259ad0.jpg

有四個(gè)不同優(yōu)先級(jí)的全局并發(fā)隊(duì)列,但在設(shè)置全局并發(fā)隊(duì)列時(shí),不直接指定優(yōu)先級(jí)。

相反,您指定服務(wù)質(zhì)量 (QoS),其中包括用戶(hù)交互、用戶(hù)啟動(dòng)、實(shí)用程序和后臺(tái),其中用戶(hù)交互具有最高優(yōu)先級(jí),而后臺(tái)具有最低優(yōu)先級(jí)。下面是QoS的使用建議。

.userInteractive 標(biāo)志任務(wù)需要被立即執(zhí)行以便提供更出色的用戶(hù)體驗(yàn)。通常用來(lái)做UI更新,事件處理等低延時(shí)的任務(wù)。該類(lèi)型的任務(wù)不應(yīng)過(guò)多。

.userInitiated 標(biāo)志任務(wù)被用戶(hù)通過(guò)UI界面創(chuàng)建,但是可以被異步執(zhí)行。通常用在用戶(hù)一個(gè)操作后需要等待,結(jié)果返回后繼續(xù)之前的操作。

.default 默認(rèn)值。用于一般性異步任務(wù)。

.utility 標(biāo)志任務(wù)需要較長(zhǎng)時(shí)間,通常會(huì)關(guān)聯(lián)一個(gè)進(jìn)度。比如:I/O、網(wǎng)絡(luò)請(qǐng)求等。

.background 標(biāo)志任務(wù)的執(zhí)行用戶(hù)不太會(huì)關(guān)心。比如:預(yù)加載數(shù)據(jù)。

與全局隊(duì)列相比,您可以使用自定義隊(duì)列執(zhí)行以下任務(wù):

您可以指定一個(gè)對(duì)您有意義的標(biāo)簽,以便在自定義隊(duì)列上進(jìn)行調(diào)試

你可以暫停和重啟: queue.suspend() queue.resume()

提交柵欄任務(wù): queue.async(flags: .barrier) { ... }

主隊(duì)列

主隊(duì)列是一個(gè)全局可用的串行隊(duì)列,它在應(yīng)用程序的主線程上執(zhí)行任務(wù)

該隊(duì)列與應(yīng)用程序的運(yùn)行循環(huán)一起工作,以將排隊(duì)任務(wù)和運(yùn)行循環(huán)的其他事件源任務(wù)交錯(cuò)執(zhí)行。因?yàn)樗趹?yīng)用程序的主線程上運(yùn)行,所以主隊(duì)列通常用作應(yīng)用程序的關(guān)鍵同步點(diǎn)。

同步與異步

我們已經(jīng)學(xué)習(xí)了如何在隊(duì)列上串行或并發(fā)地執(zhí)行任務(wù)。使用 GCD,您還可以同步或異步的調(diào)度隊(duì)列。

一般來(lái)說(shuō),同步函數(shù)(sync)在任務(wù)完成后將控制權(quán)返回給調(diào)用者。而異步函數(shù)(async)會(huì)在函數(shù)調(diào)用后,立即將將控制權(quán)返回給調(diào)用者,它不會(huì)等等任務(wù)完成。

e2d668da-26f1-11ee-962d-dac502259ad0.jpg

如上圖,您在并發(fā)全局隊(duì)列上執(zhí)行耗時(shí)的任務(wù),但主線程仍然很忙,因?yàn)槟谥骶€程 main 上同步地在分派任務(wù),它會(huì)一直等到任務(wù)執(zhí)行完成。

e2ec1824-26f1-11ee-962d-dac502259ad0.jpg

如上圖:我們異步的分派任務(wù),它立即返回到主線程,主線程將首先打印,隊(duì)列上的列任務(wù)將并發(fā)執(zhí)行。

預(yù)防死鎖

在并發(fā)計(jì)算中,死鎖是一個(gè)組的每個(gè)成員都在等待另一個(gè)成員(包括它自己)采取行動(dòng)的狀態(tài)

e306bb7a-26f1-11ee-962d-dac502259ad0.jpg

在上圖中,queue是一個(gè)串行隊(duì)列,通過(guò)async派發(fā)的任務(wù)A,通過(guò)sync派發(fā)了任務(wù)B。此時(shí)A會(huì)等待B完成后繼續(xù)向下,而B(niǎo)在A沒(méi)有完成之前是不會(huì)開(kāi)始。這就造成了死鎖。

e31cc564-26f1-11ee-962d-dac502259ad0.jpg

同樣,上圖的主隊(duì)列任務(wù)A(viewDidLoad方法)使用sync派發(fā)任務(wù)B,也會(huì)造成相互等待從而死鎖。

DispatchWorkItem

DispatchWorkItem是一項(xiàng)任務(wù)的包裝器,可以多次使用,也可以取消。

letqueue=DispatchQueue(label:"com.swiftpal.dispatch.workItem")

//Createaworkitem
letworkItem=DispatchWorkItem(){
print("StoredTask")
}

//Task1
queue.async(execute:workItem)

//Task2
queue.asyncAfter(deadline:DispatchTime.now()+1,execute:workItem)

//WorkItemCancel
workItem.cancel()

//Task3
queue.async(execute:workItem)

ifitem.isCancelled{
print("Taskwascancelled")
}

這里我們創(chuàng)建了一個(gè)串行隊(duì)列,又創(chuàng)建了一個(gè)DispatchWorkItem,它只包含一句代碼。

接下來(lái),我們?cè)谌∠蝿?wù)之前派發(fā)了該任務(wù)兩次,之后再次派發(fā)該任務(wù)。但是對(duì)于輸出,我們只會(huì)看到一次Stored task。






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 處理器
    +關(guān)注

    關(guān)注

    68

    文章

    19102

    瀏覽量

    228819
  • 控制器
    +關(guān)注

    關(guān)注

    112

    文章

    16105

    瀏覽量

    177082
  • QoS
    QoS
    +關(guān)注

    關(guān)注

    1

    文章

    136

    瀏覽量

    44730
  • 調(diào)度器
    +關(guān)注

    關(guān)注

    0

    文章

    98

    瀏覽量

    5232

原文標(biāo)題:Swift 并發(fā)編程一

文章出處:【微信號(hào):AndroidPush,微信公眾號(hào):Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    并發(fā)并行、進(jìn)程、線程和協(xié)程的區(qū)別

    希望的是能一次性預(yù)存很多批處理任務(wù)進(jìn)入內(nèi)存,然后通過(guò)一定的處理規(guī)則指定(作業(yè)調(diào)度算法)來(lái)讓這些批處理任務(wù)劃分CPU的時(shí)間,這樣CPU的狀態(tài)就像是第一秒執(zhí)行A任務(wù),第二秒執(zhí)行B任務(wù),這樣看起來(lái),A任務(wù)和B任務(wù)就像是同時(shí)在進(jìn)行。這個(gè)模式,就叫做
    發(fā)表于 08-05 08:24

    Python中的并行性和并發(fā)性分析

      在Python編程語(yǔ)言當(dāng)中,很多人對(duì)Python中的并行性和并發(fā)性不了解。今天我們將討論python中的并發(fā)并行性www.zpedu.
    發(fā)表于 08-21 17:45

    Lite Actor:方舟Actor并發(fā)模型的輕量級(jí)優(yōu)化

    執(zhí)行的能力,如圖1所示,在一個(gè)時(shí)間段中可能有多個(gè)任務(wù)都處于已啟動(dòng)運(yùn)行到運(yùn)行完畢之間,同時(shí),并發(fā)單元也可以在多核設(shè)備下并行執(zhí)行,可以極大地提高多核設(shè)備的運(yùn)行性能。 圖1
    發(fā)表于 07-18 12:00

    移動(dòng)應(yīng)用高級(jí)語(yǔ)言開(kāi)發(fā)——并發(fā)探索

    (Actor、函數(shù)式編程),具有容錯(cuò)性好、特定場(chǎng)景性能表現(xiàn)很好且易于維護(hù)和測(cè)試的優(yōu)勢(shì),但也存在應(yīng)用場(chǎng)景有限、不適合細(xì)粒度并行等短板。 03?移動(dòng)應(yīng)用框架并發(fā) 3.1??Dart 語(yǔ)言 Dart是一門(mén)新的
    發(fā)表于 08-28 17:08

    HarmonyOS如何使用異步并發(fā)能力進(jìn)行開(kāi)發(fā)

    并發(fā)是指異步代碼在執(zhí)行到一定程度后會(huì)被暫停,以便在未來(lái)某個(gè)時(shí)間點(diǎn)繼續(xù)執(zhí)行,這種情況下,同一時(shí)間只有一段代碼在執(zhí)行。 ● 多線程并發(fā)允許在
    發(fā)表于 09-22 17:35

    Java并發(fā)編程實(shí)戰(zhàn)

    Java并發(fā)編程實(shí)戰(zhàn)
    發(fā)表于 03-19 11:24 ?7次下載

    并行并發(fā)哪個(gè)好?并行并發(fā)的概念和區(qū)別

    摘要:并發(fā)并行是兩個(gè)既相似而又不相同的概念:并發(fā)性,又稱(chēng)共行性,是指能處理多個(gè)同時(shí)性活動(dòng)的能力;并行是指同時(shí)發(fā)生的兩個(gè)并發(fā)事件,具有
    發(fā)表于 12-08 09:12 ?6.6w次閱讀
    <b class='flag-5'>并行</b>和<b class='flag-5'>并發(fā)</b>哪個(gè)好?<b class='flag-5'>并行</b>和<b class='flag-5'>并發(fā)</b>的概念和區(qū)別

    七種常見(jiàn)的并發(fā)編程模型簡(jiǎn)介

    1. 線程與鎖 線程與鎖模型有很多眾所周知的不足,但仍是其他模型的技術(shù)基礎(chǔ),也是很多并發(fā)軟件開(kāi)發(fā)的首選。 2. 函數(shù)式編程 函數(shù)式編程日漸重要的原因之一,是其對(duì)并發(fā)
    的頭像 發(fā)表于 03-15 17:21 ?4610次閱讀

    JAVA并發(fā)編程實(shí)踐

    JAVA并發(fā)編程實(shí)踐資料免費(fèi)下載。
    發(fā)表于 06-01 15:31 ?15次下載

    Java并發(fā)編程的藝術(shù)

    Java并發(fā)編程的藝術(shù)說(shuō)明。
    發(fā)表于 06-01 15:31 ?16次下載

    用于MCU上的代碼下載與執(zhí)行并發(fā)并行XIP閃存和SRAM設(shè)計(jì)

    電子發(fā)燒友網(wǎng)站提供《用于MCU上的代碼下載與執(zhí)行并發(fā)并行XIP閃存和SRAM設(shè)計(jì).zip》資料免費(fèi)下載
    發(fā)表于 09-05 17:14 ?3次下載
    用于MCU上的代碼下載與<b class='flag-5'>執(zhí)行</b>的<b class='flag-5'>并發(fā)</b><b class='flag-5'>并行</b>XIP閃存和SRAM設(shè)計(jì)

    NVIDIA Triton 系列文章(10):模型并發(fā)執(zhí)行

    前面已經(jīng)做好了每個(gè)推理模型的基礎(chǔ)配置,基本上就能正常讓 Triton 服務(wù)器使用這些獨(dú)立模型進(jìn)行推理。接下來(lái)的重點(diǎn),就是要讓設(shè)備的計(jì)算資源盡可能地充分使用,首先第一件事情就是模型并發(fā)執(zhí)行
    的頭像 發(fā)表于 01-05 11:55 ?1077次閱讀

    Java并發(fā)包之CAS介紹

    首先,用1000個(gè)客戶(hù)端進(jìn)程來(lái)模擬并發(fā),并使用信號(hào)量Semaphore 控制同時(shí)100個(gè)線程并發(fā)執(zhí)行,采用同步器CountDownLatch 確保并發(fā)線程總數(shù)
    的頭像 發(fā)表于 06-09 15:55 ?599次閱讀
    Java<b class='flag-5'>并發(fā)</b>包之CAS介紹

    shell腳本實(shí)現(xiàn)并發(fā)多進(jìn)程

    。 使用xargs命令:xargs命令可以從標(biāo)準(zhǔn)輸入中讀取數(shù)據(jù),并將其作為參數(shù)傳遞給其他命令??梢詫?b class='flag-5'>需要并發(fā)執(zhí)行的命令與xargs結(jié)合使用,以實(shí)現(xiàn)多進(jìn)程并發(fā)
    的頭像 發(fā)表于 11-08 10:20 ?1234次閱讀

    操作系統(tǒng)上并行并發(fā)的區(qū)別

    理解并發(fā)、并行的例子 先舉例子來(lái)理解這2個(gè)概念的區(qū)別。 老師讓兩個(gè)同學(xué)去辦公室談話。如果這兩同學(xué)(進(jìn)程)是并列跨過(guò)辦公室門(mén)(CPU)的,那么就是并行。如果同學(xué)A先進(jìn)同學(xué)B后進(jìn)入(或者先B后A),或者
    的頭像 發(fā)表于 11-09 14:42 ?1875次閱讀
    操作系統(tǒng)上<b class='flag-5'>并行</b>和<b class='flag-5'>并發(fā)</b>的區(qū)別