欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python和Golang協(xié)程的區(qū)別

 更新時(shí)間:2023年12月25日 10:46:02   作者:張寶劍?PFinalClub  
這篇文章主要為大家介紹了Python和Golang協(xié)程的區(qū)別示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

背景

最近在做后端服務(wù) Python 到 Go 的遷移和重構(gòu),這兩種語言里,最大的特色和優(yōu)勢(shì)就是都支持協(xié)程。之前主要做python的性能優(yōu)化和架構(gòu)優(yōu)化,一開始覺得兩個(gè)協(xié)程原理和應(yīng)用應(yīng)該差不多,后來發(fā)現(xiàn)還是有很大的區(qū)別,今天就在這里總結(jié)一下。

什么是協(xié)程

在說它們兩者區(qū)別前,我們首先聊一下什么是協(xié)程,好像它沒有一個(gè)官方的定義,那就結(jié)合平時(shí)的應(yīng)用經(jīng)驗(yàn)和學(xué)習(xí)內(nèi)容來談?wù)勛约旱睦斫狻?/p>

協(xié)程,其實(shí)可以理解為一種特殊的程序調(diào)用。特殊的是在執(zhí)行過程中,在子程序(或者說函數(shù))內(nèi)部可中斷,然后轉(zhuǎn)而執(zhí)行別的子程序,在適當(dāng)?shù)臅r(shí)候再返回來接著執(zhí)行。

注意,它有兩個(gè)特征:

  • 可中斷,這里的中斷不是普通的函數(shù)調(diào)用,而是類似CPU的中斷,CPU在這里直接釋放轉(zhuǎn)到其他程序斷點(diǎn)繼續(xù)執(zhí)行。

  • 可恢復(fù),等到合適的時(shí)候,可以恢復(fù)到中斷的地方繼續(xù)執(zhí)行,至于什么是合適的時(shí)候,我們后面再探討。

和進(jìn)程線程的區(qū)別

上面兩個(gè)特點(diǎn)就導(dǎo)致了它相對(duì)于線程和進(jìn)程切換來說極高的執(zhí)行效率,為什么這么說呢?我們先老生常談地說一下進(jìn)程和線程。

進(jìn)程是操作系統(tǒng)資源分配的基本單位,線程是操作系統(tǒng)調(diào)度和執(zhí)行的最小單位。這兩句應(yīng)該是我們最常聽到的兩句話,拆開來說,進(jìn)程是程序的啟動(dòng)實(shí)例,擁有代碼和打開的文件資源、數(shù)據(jù)資源、獨(dú)立的內(nèi)存空間。線程從屬于進(jìn)程,是程序的實(shí)際執(zhí)行者,一個(gè)進(jìn)程至少包含一個(gè)主線程,也可以有更多的子線程,線程擁有自己的??臻g。無論是進(jìn)程還是線程,都是由操作系統(tǒng)所管理和切換的。

我們?cè)賮砜磪f(xié)程,它又叫做微線程,但其實(shí)它和進(jìn)程還有線程完全不是一個(gè)維度上的概念。進(jìn)程和線程的切換完全是用戶無感,由操作系統(tǒng)控制,從用戶態(tài)到內(nèi)核態(tài)再到用戶態(tài)。而協(xié)程的切換完全是程序代碼控制的,在用戶態(tài)的切換,就像函數(shù)回調(diào)的消耗一樣,在線程的棧內(nèi)即可完成。

Python的協(xié)程(coroutine)

Python 的協(xié)程其實(shí)是我們通常意義上的協(xié)程 coroutine。

從概念上來講,Python 的協(xié)程同樣是在適當(dāng)?shù)臅r(shí)候可中斷可恢復(fù)。那么什么是適當(dāng)?shù)臅r(shí)候呢,就是你認(rèn)為適當(dāng)?shù)臅r(shí)候,因?yàn)槌绦蛟谀睦锇l(fā)生協(xié)程切換完全控制在開發(fā)者手里。當(dāng)然,對(duì)于 Python 來說,由于 GIL 鎖,在 CPU 密集的代碼上做協(xié)程切換是沒啥意義的,CPU 本來就在忙著沒偷懶,切換到其他協(xié)程,也只是在單核內(nèi)換個(gè)地方忙而已。很明顯,我們應(yīng)該在 IO 密集的地方來起協(xié)程,這樣可以讓 CPU 不再空等轉(zhuǎn)而去別的地方干活,才能真正發(fā)揮協(xié)程的威力。

從實(shí)現(xiàn)上來講,如果熟知了 Python 生成器,還可以將協(xié)程理解為生成器+調(diào)度策略,生成器中的 yield 關(guān)鍵字,就可以讓生成器函數(shù)發(fā)生中斷,而調(diào)度策略,可以驅(qū)動(dòng)著協(xié)程的執(zhí)行和恢復(fù)。這樣就實(shí)現(xiàn)了協(xié)程的概念。這里的調(diào)度策略可能有很多種,簡(jiǎn)單的例如忙輪循:while True,更簡(jiǎn)單的甚至是一個(gè) for 循環(huán)。就可以驅(qū)動(dòng)生成器的運(yùn)行,因?yàn)樯善鞅旧硪彩强傻?。?fù)雜的比如可能是基于 epool 的事件循環(huán),在 Python2 的 tornado 中,以及 Python3 的 asyncio 中,都對(duì)協(xié)程的用法做了更好的封裝,通過 yield 和 await 就可以使用協(xié)程,通過事件循環(huán)監(jiān)控文件描述符狀態(tài)來驅(qū)動(dòng)協(xié)程恢復(fù)執(zhí)行。

我們看一個(gè)簡(jiǎn)單的協(xié)程:

import time
def consumer():
    r = ''
    while True:
        n = yield r
        if not n:
            return
        print('[CONSUMER] Consuming %s...' % n)
        time.sleep(1)
        r = '200 OK'
def produce(c):
    c.next()
    n = 0
    while n < 5:
        n = n + 1
        print('[PRODUCER] Producing %s...' % n)
        r = c.send(n)
        print('[PRODUCER] Consumer return: %s' % r)
    c.close()
if __name__ == '__main__':
    c = consumer()
    produce(c)

很明顯這是一個(gè)傳統(tǒng)的生產(chǎn)者-消費(fèi)者模型,這里 consumer 函數(shù)就是一個(gè)協(xié)程(生成器),它在 n = yield r 的地方發(fā)生中斷,生產(chǎn)者 produce 中的 c.send(n) ,可以驅(qū)動(dòng)協(xié)程的恢復(fù),并且向協(xié)程函數(shù)傳遞數(shù)據(jù)n,接收返回結(jié)果r。而while n < 5,就是我們所說的調(diào)度策略。在生產(chǎn)中,這種模式很適合我們來做一些 pipeline 數(shù)據(jù)的消費(fèi),我們不需要寫死幾個(gè)生產(chǎn)者進(jìn)程幾個(gè)消費(fèi)者進(jìn)程,而是用這種協(xié)程的方式,來實(shí)現(xiàn)CPU動(dòng)態(tài)地分配調(diào)度。

如果你看過上篇文章的話,是不是發(fā)現(xiàn)這個(gè) Go 中流水線模型有點(diǎn)像呢,也是生產(chǎn)者和消費(fèi)者間進(jìn)行通信,但 Go是通過 channe l這種安全的數(shù)據(jù)結(jié)構(gòu),為什么 Python 不需要呢,因?yàn)?Python 的協(xié)程是在單線程內(nèi)切換本身就是安全的,換句話說,協(xié)程間本身就是串行執(zhí)行的。而 Go 則不然。思考一個(gè)有意思的問題,如果我們將 Go 流水線模型中channel設(shè)置為無緩沖區(qū)時(shí),生產(chǎn)者絕對(duì)驅(qū)動(dòng)消費(fèi)者的執(zhí)行,是不是就跟.Python 很像了呢。

所以 Python 的協(xié)程從某種意義來說,是不是 Go 協(xié)程的一種特殊情況呢?后端在線服務(wù)中我們更常用的 Python 協(xié)程其實(shí)是在異步IO框架中使用,之前我們也提過 Python 協(xié)程在 IO 密集的系統(tǒng)中使用才能發(fā)揮它的威力。

Python協(xié)程的特點(diǎn)

  • 單線程內(nèi)切換,適用于IO密集型程序中,可以最大化IO多路復(fù)用的效果。

  • 無法利用多核。

  • 協(xié)程間完全同步,不會(huì)并行。不需要考慮數(shù)據(jù)安全。

  • 用法多樣,可以用在 web 服務(wù)中,也可用在 pipeline 數(shù)據(jù)/任務(wù)消費(fèi)中

Golang的協(xié)程(goroutine)

Golang 的協(xié)程就和傳統(tǒng)意義上的協(xié)程不大一樣了,兼具協(xié)程和線程的優(yōu)勢(shì)。這也是 Golang 最大的特色,就是從語言層面支持并發(fā)。Go語言里,啟動(dòng)一個(gè)goroutine很容易:go function 就行。

同樣從概念上來講,Golang 的協(xié)程同樣是在適當(dāng)?shù)臅r(shí)候可中斷可恢復(fù)。當(dāng)協(xié)程中發(fā)生 channel 讀寫的阻塞或者系統(tǒng)調(diào)用時(shí),就會(huì)切換到其他協(xié)程。具體的代碼示例可以看上篇文章,就不再贅述了。

從實(shí)現(xiàn)上來說,Goroutine 可以在多核上運(yùn)行,從而實(shí)現(xiàn)協(xié)程并行,我們先直接看下 Golang 的調(diào)度模型 MPG。

M指的是Machine,一個(gè)M直接關(guān)聯(lián)了一個(gè)內(nèi)核線程。由操作系統(tǒng)管理。P指的是processor,代表了M所需的上下文環(huán)境,也是處理用戶級(jí)代碼邏輯的處理器。它負(fù)責(zé)銜接 M 和 G 的調(diào)度上下文,將等待執(zhí)行的G與M對(duì)接。G指的是Goroutine,其實(shí)本質(zhì)上也是一種輕量級(jí)的線程。包括了調(diào)用棧,重要的調(diào)度信息,例如 channel 等。

每次 go 調(diào)用的時(shí)候,都會(huì):

  • 創(chuàng)建一個(gè) G 對(duì)象,加入到本地隊(duì)列或者全局隊(duì)列

  • 如果還有空閑的 P,則創(chuàng)建一個(gè) M

  • M 會(huì)啟動(dòng)一個(gè)底層線程,循環(huán)執(zhí)行能找到的 G 任務(wù)

  • G 任務(wù)的執(zhí)行順序是,先從本地隊(duì)列找,本地沒有則從全局隊(duì)列找(一次性轉(zhuǎn)移(全局 G 個(gè)數(shù)/ P 個(gè)數(shù))個(gè),再去其它P中找(一次性轉(zhuǎn)移一半)

對(duì)于上面的第2-3步,創(chuàng)建一個(gè) M,其過程:

  • 先找到一個(gè)空閑的 P ,如果沒有則直接返回,(哈哈,這個(gè)地方就保證了進(jìn)程不會(huì)占用超過自己設(shè)定的 CPU 個(gè)數(shù))

  • 調(diào)用系統(tǒng) api 創(chuàng)建線程,不同的操作系統(tǒng),調(diào)用不一樣,其實(shí)就是和 C 語言創(chuàng)建過程是一致的

  • 然后創(chuàng)建的這個(gè)線程里面才是真正做事的,循環(huán)執(zhí)行 G 任務(wù)

當(dāng)協(xié)程發(fā)生阻塞切換時(shí):

  • M0 出讓 P

  • 創(chuàng)建 M1 接管 P 及其任務(wù)隊(duì)列繼續(xù)執(zhí)行其他 G。

  • 當(dāng)阻塞結(jié)束后,M0 會(huì)嘗試獲取空閑的 P,失敗的話,就把當(dāng)前的 G 放到全局隊(duì)列的隊(duì)尾。

這里我們需要注意三點(diǎn):

1、M 與 P 的數(shù)量沒有絕對(duì)關(guān)系,一個(gè) M 阻塞,P 就會(huì)去創(chuàng)建或者切換另一個(gè) M,所以,即使P的默認(rèn)數(shù)量是 1,也有可能會(huì)創(chuàng)建很多個(gè) M 出來。

2、P 何時(shí)創(chuàng)建:在確定了 P 的最大數(shù)量 n 后,運(yùn)行時(shí)系統(tǒng)會(huì)根據(jù)這個(gè)數(shù)量創(chuàng)建 n 個(gè) P。

3、M 何時(shí)創(chuàng)建:沒有足夠的 M 來關(guān)聯(lián)P并運(yùn)行其中的可運(yùn)行的 G。比如所有的 M 此時(shí)都阻塞住了,而 P 中還有很多就緒任務(wù),就會(huì)去尋找空閑的 M,而沒有空閑的,就會(huì)去創(chuàng)建新的 M。

Golang協(xié)程的特點(diǎn)

  • 協(xié)程間需要保證數(shù)據(jù)安全,比如通過channel或鎖。

  • 可以利用多核并行執(zhí)行。

  • 協(xié)程間不完全同步,可以并行運(yùn)行,具體要看channel的設(shè)計(jì)。

  • 搶占式調(diào)度,可能無法實(shí)現(xiàn)公平。

coroutine(Python)和 Goroutine(Golang)的區(qū)別

除了 Python,C#, Lua 語言都支持 coroutine 特性。coroutine 與 goroutine 在名字上類似,都是可中斷可恢復(fù)的協(xié)程,它們之間最大的不同是,goroutine 可能在多核上發(fā)生并行執(zhí)行,單但 coroutine 始終是順序執(zhí)行。也基于此,我們應(yīng)該清楚 coroutine 適用于 IO 密集程序中,而 goroutine 在 IO 密集和 CPU 密集中都有很好的表現(xiàn)。不過話說回來,Golang 就一定比 Python 快么,假如在完全I(xiàn)O并發(fā)密集的程序中,Python 的表現(xiàn)反而更好,因?yàn)閱尉€程內(nèi)的協(xié)程切換效率更高。

從運(yùn)行機(jī)制上來說,coroutine 的運(yùn)行機(jī)制屬于協(xié)作式任務(wù)處理, 程序需要主動(dòng)交出控制權(quán),宿主才能獲得控制權(quán)并將控制權(quán)交給其他 coroutine。如果開發(fā)者無意間或者故意讓應(yīng)用程序長時(shí)間占用 CPU,操作系統(tǒng)也無能為力,表現(xiàn)出來的效果就是計(jì)算機(jī)很容易失去響應(yīng)或者死機(jī)。goroutine 屬于搶占式任務(wù)處理,已經(jīng)和現(xiàn)有的多線程和多進(jìn)程任務(wù)處理非常類似, 雖然無法控制自己獲取高優(yōu)先度支持。但如果發(fā)現(xiàn)一個(gè)應(yīng)用程序長時(shí)間大量地占用 CPU,那么用戶有權(quán)終止這個(gè)任務(wù)。

從協(xié)程:線程的對(duì)應(yīng)方式來看:

  • N:1,Python 協(xié)程模式,多個(gè)協(xié)程在一個(gè)線程中切換。在 IO 密集時(shí)切換效率高,但沒有用到多核

  • 1:1,Java 多線程模式,每個(gè)協(xié)程只在一個(gè)線程中運(yùn)行,這樣協(xié)程和線程沒區(qū)別,雖然用了多核,但是線程切換開銷大。

  • M:N,Golang 模式,多個(gè)協(xié)程在多個(gè)線程上切換,既可以用到多核,又可以減少切換開銷。(當(dāng)都是 CPU 密集時(shí),在多核上切換好,當(dāng)都是io密集時(shí),在單核上切換好)。

從協(xié)程通信和調(diào)度機(jī)制來看:

其他文章的對(duì)比

http://www.dbjr.com.cn/article/160979.htm

  • async是非搶占式的,一旦開始采用 async 函數(shù),那么你整個(gè)程序都必須是 async 的,不然總會(huì)有阻塞的地方(一遇阻塞對(duì)于沒有實(shí)現(xiàn)異步特性的庫就無法主動(dòng)讓調(diào)度器調(diào)度其他協(xié)程了),也就是說 async 具有傳染性。

  • Python 整個(gè)異步編程生態(tài)的問題,之前標(biāo)準(zhǔn)庫和各種第三方庫的阻塞性函數(shù)都不能用了,如:requests,redis.py,open 函數(shù)等。所以 Python3.5后加入?yún)f(xié)程的最大問題不是不好用,而是生態(tài)環(huán)境不好,歷史包袱再次上演,動(dòng)態(tài)語言基礎(chǔ)上再加上多核之間的任務(wù)調(diào)度,應(yīng)該是很難的技術(shù)吧,真心希望python4.0能優(yōu)化或者放棄GIL鎖,使用多核提升性能。

  • goroutine 是 go 與生俱來的特性,所以幾乎所有庫都是可以直接用的,避免了 Python 中需要把所有庫重寫一遍的問題。

  • goroutine 中不需要顯式使用 await 交出控制權(quán),但是 Go 也不會(huì)嚴(yán)格按照時(shí)間片去調(diào)度 goroutine,而是會(huì)在可能阻塞的地方插入調(diào)度。goroutine 的調(diào)度可以看做是半搶占式的。

以上就是Python和Golang協(xié)程的區(qū)別的詳細(xì)內(nèi)容,更多關(guān)于Python和Golang協(xié)程的區(qū)別的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • python2.7實(shí)現(xiàn)FTP文件下載功能

    python2.7實(shí)現(xiàn)FTP文件下載功能

    這篇文章主要為大家詳細(xì)介紹了python 2.7 實(shí)現(xiàn)FTP文件下載功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • 瀏覽器常用基本操作之python3+selenium4自動(dòng)化測(cè)試(基礎(chǔ)篇3)

    瀏覽器常用基本操作之python3+selenium4自動(dòng)化測(cè)試(基礎(chǔ)篇3)

    瀏覽器常用基本操作有很多種,今天給大家介紹python3+selenium4自動(dòng)化測(cè)試的操作方法,是最最基礎(chǔ)的一篇,對(duì)python3 selenium4自動(dòng)化測(cè)試相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-05-05
  • Python實(shí)現(xiàn)找到同名文件并復(fù)制到其他文件夾中

    Python實(shí)現(xiàn)找到同名文件并復(fù)制到其他文件夾中

    這篇文章主要為大家介紹了如何基于Python語言,實(shí)現(xiàn)依據(jù)某一文件夾中大量文件的名稱復(fù)制另一文件夾中的同名文件,文中的示例代碼簡(jiǎn)潔易懂,需要的可以參考一下
    2023-05-05
  • Python+Pygame實(shí)現(xiàn)經(jīng)典魂斗羅游戲

    Python+Pygame實(shí)現(xiàn)經(jīng)典魂斗羅游戲

    《魂斗羅》(Contra)是由Konami于1987年推出的一系列卷軸射擊類單機(jī)游戲。本文將利用Python中的Pygame庫實(shí)現(xiàn)這一經(jīng)典游戲,感興趣的可以了解一下
    2022-05-05
  • Python字符串檢索方式

    Python字符串檢索方式

    文章介紹了Python中字符串查找的六種方法:count()、find()、index()、rindex()、startswith()和endswith(),并詳細(xì)解釋了每個(gè)方法的語法和運(yùn)行結(jié)果
    2024-11-11
  • django之導(dǎo)入并執(zhí)行自定義的函數(shù)模塊圖解

    django之導(dǎo)入并執(zhí)行自定義的函數(shù)模塊圖解

    這篇文章主要介紹了django之導(dǎo)入并執(zhí)行自定義的函數(shù)模塊圖解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-04-04
  • Python使用LRU緩存策略進(jìn)行緩存的方法步驟

    Python使用LRU緩存策略進(jìn)行緩存的方法步驟

    本文主要介紹了Python使用LRU緩存策略進(jìn)行緩存的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-05-05
  • python?Socket無限發(fā)送接收數(shù)據(jù)方式

    python?Socket無限發(fā)送接收數(shù)據(jù)方式

    這篇文章主要介紹了python?Socket無限發(fā)送接收數(shù)據(jù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • cmd運(yùn)行python文件時(shí)對(duì)結(jié)果進(jìn)行保存的方法

    cmd運(yùn)行python文件時(shí)對(duì)結(jié)果進(jìn)行保存的方法

    今天小編就為大家分享一篇cmd運(yùn)行python文件時(shí)對(duì)結(jié)果進(jìn)行保存的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • Python?calendar模塊詳情

    Python?calendar模塊詳情

    這篇文章主要介紹了?Python?calendar模塊,Python?專門為了處理日歷提供了calendar日歷模塊,下面文章基于time模塊和datetime模塊展開,具有一定的參考價(jià)值,需要的朋友可以參考一下
    2021-11-11

最新評(píng)論