2022年,虎年虎虎生威~!
前言
Android 開發(fā)者來說 Kotlin 語言已經(jīng)是很熟悉的了,但 Kotlin 中的 協(xié)程 不了解的同學(xué)可能還有很多。
閱讀網(wǎng)絡(luò)上大多數(shù)文章得到的關(guān)于 協(xié)程 幾個關(guān)鍵詞:
- 像是線程;
- 不是線程;
- 用戶態(tài);
- 協(xié)作式;
感覺很懵逼,我就問一個 協(xié)程 而已為什么出現(xiàn)這么多奇奇怪該的名詞。
協(xié)程簡介
協(xié)程(英語:coroutine)是計算機程序的一類組件,推廣了協(xié)作式多任務(wù)的子例程,允許執(zhí)行被掛起與被恢復(fù)。 相對子例程而言,協(xié)程更為一般和靈活,但在實踐中使用沒有子例程那樣廣泛。 協(xié)程更適合于用來實現(xiàn)彼此熟悉的程序組件,如協(xié)作式多任務(wù)、異常處理、事件循環(huán)、迭代器、無限列表和管道。
電腦物理硬件
說 協(xié)程 之前我們先聊一下計算機硬件相關(guān)的知識。
物理 cpu 數(shù)
指主板上實際插入的 cpu 硬件個數(shù)(socket)。(但是這一概念經(jīng)常被泛泛的說成是 cpu 數(shù),這很容易導(dǎo)致與 core 數(shù),processor 數(shù)等概念混淆,所以此處強調(diào)是物理 cpu 數(shù))。
由于在主板上引入多個 cpu 插槽需要更復(fù)雜的硬件支持(連接不同插槽的 cpu 到內(nèi)存和其他資源),通常只會在服務(wù)器上才這樣做。在家用電腦中,一般主板上只會有一個 cpu 插槽。
核數(shù)
一開始,每個物理 cpu 上只有一個核心 a single core ,對操作系統(tǒng)而言,也就是同一時刻只能運行一個進程/線程。 為了提高性能,cpu 廠商開始在單個物理 cpu 上增加核心(實實在在的硬件存在),也就出現(xiàn)了雙核心 cpu(dual-core cpu)以及多核心 cpu(multiple cores),這樣一個雙核心 cpu 就是同一時刻能夠運行兩個進程/線程的。
超線程技術(shù)
同時多線程技術(shù)(simultaneous multithreading)
超線程技術(shù)(hyper–threading/HT)
本質(zhì)一樣,是為了提高單個 core 同一時刻能夠執(zhí)行的多線程數(shù)的技術(shù)(充分利用單個 core 的計算能力,盡量讓其“一刻也不得閑”)。
simultaneous multithreading 縮寫是 SMT,AMD 和其他 cpu 廠商的稱呼。 hyper–threading 是 Intel 的稱呼,可以認為 hyper–threading 是 SMT 的一種具體技術(shù)實現(xiàn)。
所以可以這樣說:某款采用 SMT 技術(shù)的 4核心 AMD cpu 提供了 8線程 同時執(zhí)行的能力;某款采用 HT 技術(shù)的 2 核心 Intel cpu 提供了 4 線程 同時執(zhí)行的能力。
總的邏輯
cpu數(shù) = 物理cpu數(shù) * 每顆物理cpu的核心數(shù) * 每個核心的超線程數(shù)
線程和協(xié)程
講 協(xié)程 的時候絕對不能不提 線程 。
線程 是操作系統(tǒng)能夠進行運算的最小單位。
在之前一般情況下 CPU 的每個核心同一時間只能執(zhí)行一個線程,除了現(xiàn)在比較新的 CPU 擁有上面說的使用 SMT 或者 HT 技術(shù)。
但 CPU 的核心數(shù)和 線程 的個數(shù)沒有必然關(guān)系。舉個很簡單的例子,我一段代碼可以一直創(chuàng)建100個線程。
CPU 根本不理解自己執(zhí)行的指令屬于哪個 線程,CPU 也不需要理解這些,它只需只需當(dāng)前操作系統(tǒng)給它分配的指令就行。
在單核 CPU 時代所有的多線程其實都是多任務(wù),多個任務(wù)交替使用 CPU資源 。
有了多核之后,運行在兩個線程的任務(wù)才實現(xiàn)正真的并行,但電腦的實際核數(shù)永遠也達不到我們運算需要的任務(wù)數(shù)量。所以多個任務(wù)交替使用 CPU資源 這種情況一直存在,但我們知道 CPP 切換執(zhí)行線程的上下文都是需要消耗資源的,任務(wù)數(shù)量越多不一定執(zhí)行效率更高。對于計算密集型的程序有的建議是設(shè)置線程的最佳數(shù)量為 CPU 可執(zhí)行線程數(shù)的 1.5倍 或者 1倍+1 。
在這個時候我們想到能不能在異步任務(wù)之間切換的時候不切換 CPU 的上下文狀態(tài),這樣可以減少很多資源的浪費?;蛘咴?CPU 長時間執(zhí)行 I/O操作 的時候讓其他例程先執(zhí)行,提供資源的利用率。
協(xié)程 就在這個時候產(chǎn)生了,協(xié)作式執(zhí)行多任務(wù)的子例程。
這時候我們已經(jīng)對 協(xié)程 有了初步的了解了,回頭想想文章開頭4個描述 協(xié)程 的說明。
- 像是線程:在部分程序執(zhí)行的過程中,協(xié)程的并發(fā)執(zhí)行就是利用的多線程技術(shù)(例如:沒有進行改版的
Java程序)。所以說它像是線程; - 不是線程:并發(fā)任務(wù)的調(diào)度不是都通過操作系統(tǒng)級別線程切換執(zhí)行,而是程序本身支持單個線程的多個并發(fā)任務(wù)。所以也可以說它不是線程,可以叫它們纖程
Fiber,或者綠色線程GreenThread。正如一個進程可以擁有多個線程一樣,一個線程也可以擁有多個協(xié)程。 - 用戶態(tài):不是系統(tǒng)級別的線程而且能自主執(zhí)行異步任務(wù),這種由程序員自己寫程序來管理的輕量級線程叫做用戶空間線程,具有對內(nèi)核來說不可見的特性。
- 協(xié)作式:要求每個運行中的程序,定位放棄自己的執(zhí)行權(quán)利,讓多個任務(wù)一起交替執(zhí)行。維基百科:協(xié)作式多任務(wù);
Android中的協(xié)程
上面說的 協(xié)程 減少上下文切換,提供效率,那么 Android 的 kotlin 支持協(xié)程么?
kotlin 官方文檔說:本質(zhì)上,協(xié)程是輕量級的線程。
但就目前 Kotlin-JVM 而言來說 協(xié)程 它就是線程。其本質(zhì)上還是一套基于原生 Java Thread API 的封裝。
可能后續(xù) Kotlin 的版本會有正真的協(xié)程相關(guān)的機制來代替線程。
這個時候可能我們可能就有一些疑問,既然 協(xié)程 在 Android 平臺上依舊是 線程 并沒有提示運行效率,Java 中的 Executor 和 Android 中的 AsyncTask 都能提供并發(fā)任務(wù),那么 kotlin 的 協(xié)程 它有什么用?后面會有一篇文章單獨講解~!
參考資料:
Kotlin 協(xié)程真的比 Java 線程更高效嗎?
文章到這里就全部講述完啦,若有其他需要交流的可以留言哦~!~!