久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

再談協(xié)程

 python_lover 2021-08-09

如果你對以下幾個問題有疑問,,那么本文可能會有所幫助,。

  1. 什么是協(xié)程,或者說為什么會有協(xié)程這個概念,?

  2. 怎么用,?什么時候需要用?

  3. 都有并行的意味,,那么協(xié)程和多線程有什么區(qū)別,?兩者能否相互替代?

  4. 協(xié)程底層的實現(xiàn)原理,。


1.2.3

談協(xié)程繞不開線程,,按傳統(tǒng)還得從進(jìn)程談起,不過我想業(yè)內(nèi)人員對進(jìn)程和線程應(yīng)該是耳熟能詳,,這里就簡單概括下,。

進(jìn)程擁有自己獨(dú)立的堆和棧,既不共享堆,,亦不共享棧,,進(jìn)程由操作系統(tǒng)調(diào)度;線程擁有自己獨(dú)立的棧,,共享堆(也可以有自己的私有域),,不共享棧,線程亦由操作系統(tǒng)調(diào)度,。一個進(jìn)程可以有多個線程,。

多線程一直以來是面試必考點(diǎn),雖然[web]服務(wù)端開發(fā)人員似乎從來不用直接操作線程,,其實是因為框架幫忙維護(hù)了,,開發(fā)人員只需要關(guān)心業(yè)務(wù)實現(xiàn)。這也導(dǎo)致了部分人對多線程的某些概念模糊不清。比如關(guān)于多線程的效率:在多核cpu下,,多個線程可以并行運(yùn)行在不同內(nèi)核上,,效率高;而在單核cpu中,,多個線程的并行執(zhí)行其實是一個錯覺,,因為它們都是運(yùn)行在一個內(nèi)核上,一個cpu內(nèi)核同一時間只能執(zhí)行一個進(jìn)程/線程,,因此在一個內(nèi)核上的多線程執(zhí)行其實效率反而比串行執(zhí)行低,,只是給用戶一種并發(fā)的錯覺,反而增加了線程切換的時間,。

但是效率的高低還要看線程占用cpu資源的占用率,,比如存在大量IO操作,IO比較慢,。也就是說,,如果只有單線程,那么一旦涉及到IO操作,,線程可能會被阻塞,程序的其余邏輯就只能傻等,,就算那些邏輯不依賴于這個IO操作,,此時線程對CPU的使用為0,CPU就是空閑狀態(tài),。如果是多線程,,是線程瓶頸,那么其余線程則可以使用cpu,,而非等待IO結(jié)束,。

題外話,一個空循環(huán)就能讓cpu滿載,,參看 為什么一個空的死循環(huán)會讓CPU占用達(dá)到100%,。

后來,出現(xiàn)了多路復(fù)用之類的技術(shù),,原先需要等待IO返回的線程也不需要等了,,可以和其它線程一樣忙別的事,IO返回時得到通知再處理接下去的事情,。Java的NIO和.Net的async/await就是這么干的,。

一般來說,為了避免線程頻繁創(chuàng)建銷毀帶來的性能問題,,程序里都會使用到線程池,。

然而還是在單核的場景下,事情似乎變得有點(diǎn)詭異。既然線程們現(xiàn)在都能心無旁騖地使用CPU計算,,而前面也說了,,一個cpu內(nèi)核同時只能運(yùn)行一個線程,管理多線程又是搶占式,,又是棧切換,,維護(hù)生命周期啥的,影響性能不說,,完全沒得必要嘛,,為什么不只用一個線程完成所有的計算呢。什么,,你說可能需要[偽]并行計算,?那就讓線程自己來安排咯,畢竟具體邏輯方面,,線程本身(或者說開發(fā)人員)比CPU要清楚的多,,知道什么時候該干什么,什么時候切換邏輯,,什么時候不切換,,都由線程自己說了算。于是,,協(xié)程粉墨登場,。

協(xié)程主要是針對單線程的一個概念(如Js、NodeJs,、Python由于GIL導(dǎo)致的偽多線程),,可以將其看作線程運(yùn)行時片段。和線程類似,,雖然貌似多個協(xié)程可以并行執(zhí)行,,一個時間仍然只能運(yùn)行一個。所以,,如果業(yè)務(wù)邏輯是順序相關(guān)(串行)或者各任務(wù)對反饋及時性要求不高,,那么沒必要用協(xié)程,就跟沒必要多線程一樣,。協(xié)程對比線程,,除了有更好的性能外,還讓開發(fā)人員對執(zhí)行片段有了更好的掌控,。比如Go語言,,通過阻塞條件(time.sleep()、select{}等),,我們可以手動將控制權(quán)轉(zhuǎn)移給其它的 Go 協(xié)程 , 也可以說是告訴調(diào)度器讓它去調(diào)度其它可用空閑的 Go 協(xié)程(Go如何判斷這是阻塞代碼尚未研究過),;或者通過channel調(diào)度指定協(xié)程,。

Go默認(rèn)情況下只用單線程。這就是說,,你即使開了幾百個goroutine,,系統(tǒng)中同一時間在跑的只有一個線程,也就是一個協(xié)程,。依據(jù)上面的內(nèi)容,,大家可以思考下Go為何默認(rèn)如此。我們可以通過 runtime.GOMAXPROCS() 設(shè)置的是Go語言能跑幾個線程,,講道理,,CPU幾核跑幾個線程比較合理,使用 runtime.NumCPU() 查看內(nèi)核數(shù),。

在編程層面來說,,協(xié)程的概念偏向于以同步編程的模式實現(xiàn)異步處理的編程模式,避免了多層回調(diào)代碼嵌套的問題,。

其實在很多年以前,,協(xié)程已經(jīng)被提出了,現(xiàn)在只是它煥發(fā)生機(jī)的階段,。


4

上文說了,,協(xié)程之間應(yīng)該是非順序相關(guān)的,即它們的上下文沒有強(qiáng)依賴關(guān)系,,是相對獨(dú)立的,。這里的上下文指的就是當(dāng)前的運(yùn)行棧空間,,它包括了參數(shù)、局部變量,、各寄存器的值等內(nèi)容,。在協(xié)程切換的時候,我們要想辦法將對應(yīng)的上下文投射到當(dāng)前線程的運(yùn)行棧中,,即讓線程執(zhí)行特定的上下文,。很容易想到malloc一塊臨時內(nèi)存存放掛起的協(xié)程上下文信息,resume的時候再覆蓋回去,,運(yùn)行棧在內(nèi)存中只有一處,,這就是stackless模式。相對的還有stackful模式,,在這種模式下,,每個協(xié)程都有自己的棧空間,,運(yùn)行棧指的就是當(dāng)前協(xié)程的??臻g。現(xiàn)有語言的實現(xiàn)中,Python, Kotlin等定義的就是stackless協(xié)程,, Go語言中實現(xiàn)的是stackful協(xié)程,。

對于其它沒有在語言層面直接支持協(xié)程的語言來說,由于協(xié)程涉及到底層的[堆]棧切換控制,,因此很難單純依靠現(xiàn)有語法構(gòu)建算法的方式實現(xiàn),。有人做過此類嘗試(可參看Coroutines in C),但也沒有實用性,。

能直接操作執(zhí)行堆棧并暴露api的,,現(xiàn)在市面上的語言以C/C++最為流行,基于它們也有很多開源的協(xié)程庫,。下面介紹幾種實現(xiàn)方式,。

協(xié)程分為非對稱協(xié)程和對稱協(xié)程。在非對稱協(xié)程中,,調(diào)用者和被調(diào)用者的關(guān)系是固定的,,調(diào)用者將控制流轉(zhuǎn)到被調(diào)用者,被調(diào)用者運(yùn)行完畢后只能返回到調(diào)用者,,而不能返回到其他協(xié)程,。對稱協(xié)程則不然。對稱協(xié)程可以很容易由非對稱協(xié)程來表達(dá),。且按一般的調(diào)用邏輯,,A調(diào)B,B應(yīng)返回到A,,再由A發(fā)起到C的調(diào)用,,而非B直接返回到C。因此,,目前大多數(shù)協(xié)程庫都只實現(xiàn)非對稱協(xié)程,。

  • 一種是借助glibc的ucontext,及相關(guān)的四個函數(shù)getcontext,、setcontext,、makecontext、swapcontext,,如云風(fēng)的庫,。當(dāng)然這只能在linux環(huán)境下使用,在windows下,,可以借助fiber實現(xiàn)類似的協(xié)程庫,;

  • 利用C標(biāo)準(zhǔn)庫<setjmp.h>中的setjmp、longjmp實現(xiàn)協(xié)程,。需要注意的是,,setjmp僅負(fù)責(zé)保存寄存器的值,,不負(fù)責(zé)維護(hù)其函數(shù)調(diào)用棧,這個需要另外實現(xiàn),;

  • 遵循規(guī)范從頭實現(xiàn),。如libaco,它支持 Intel386 和 x86-64 兩個平臺的Sys V ABI,,并提供了非對稱協(xié)程的實現(xiàn),。關(guān)于Sys V ABI,It is today the standard ABI used by the major Unix operating systems such as Linux, the BSD systems, and many others. The Executable and Linkable Format (ELF) is part of the System V ABI. 也就是說,,該協(xié)程庫只支持類unix系統(tǒng),;

  • 使用匯編實現(xiàn)。較為著名的是Boost庫,,協(xié)程實現(xiàn)有兩套:Corountine2和Corountine,。Corountine2在Boost v1.59被引入,Boost.Corountine目前已被標(biāo)記為deprecated,。Boost.Corountine2使用了Boost.Context,,因此要使用Boost.Corountine2,必須先編譯Boost.Context,。通用的C庫tbox的協(xié)程模塊也參照了Boost的實現(xiàn),。

關(guān)于匯編語法的平臺差異,類Unix下采用的是AT&T的匯編語法格式,,Dos/Windows下面采用的是Intel匯編語法格式,。

參考資料:

云風(fēng)-coroutine源碼解析

System V ABI

Golang 協(xié)程調(diào)度

轉(zhuǎn)載請注明本文出處:https://www.cnblogs.com/newton/p/11104187.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多