小猿圈分享-python協(xié)程與golang協(xié)程的區(qū)別

最近經(jīng)常有同學(xué)在小猿圈網(wǎng)站留言說:小猿圈網(wǎng)站上邊的課程太多了,而且全部免費斟冕,自己就忍不住都想學(xué)習(xí),尤其是學(xué)習(xí)了python和go之后景描,就有些混淆了概念伏伯,今天小猿圈就給大家分享一下python和go語言中進程捌袜、線程虏等、協(xié)程的區(qū)別适肠。

進程的定義:

進程侯养,是計算機中已運行程序的實體。程序本身只是指令柠傍、數(shù)據(jù)及其組織形式的描述,進程才是程序的真正運行實例从媚。

線程的定義:

操作系統(tǒng)能夠進行運算調(diào)度的最小單位拜效。它被包含在進程之中各谚,是進程中的實際運作單位。

進程和線程的關(guān)系:

一條線程指的是進程中一個單一順序的控制流赴穗,一個進程中可以并發(fā)多個線程愈涩,每條線程并行執(zhí)行不同的任務(wù)。

CPU

的最小調(diào)度單元是線程不是進程煤篙,所以單進程多線程也可以利用多核CPU.

協(xié)程的定義:

協(xié)程通過在線程中實現(xiàn)調(diào)度辑奈,避免了陷入內(nèi)核級別的上下文切換造成的性能損失已烤,進而突破了線程在IO上的性能瓶頸。

協(xié)程和線程的關(guān)系

協(xié)程是在語言層面實現(xiàn)對線程的調(diào)度稍计,避免了內(nèi)核級別的上下文消耗臣嚣。

python協(xié)程與調(diào)度

Python的協(xié)程源于yield指令剥哑。yield有兩個功能:

yield item用于產(chǎn)出一個值,反饋給next()的調(diào)用方怎虫。

作出讓步大审,暫停執(zhí)行生成器,讓調(diào)用方繼續(xù)工作捡鱼,直到需要使用另一個值時再調(diào)用next()酷愧。

import asyncio



async defcompute(x, y):

??? print("Compute %s + %s ..." % (x,y))

??? await asyncio.sleep(x + y)

??? return x + y



async defprint_sum(x, y):

??? result = await compute(x, y)

??? print("%s + %s = %s" % (x, y,result))



loop =asyncio.get_event_loop()

tasks =[print_sum(1, 2), print_sum(3, 4)]

loop.run_until_complete(asyncio.wait(tasks))

loop.close()

協(xié)程是對線程的調(diào)度溶浴,yield類似惰性求值方式可以視為一種流程控制工具,實現(xiàn)協(xié)作式多任務(wù),在Python3.5正式引入了 async/await表達式闯两,使得協(xié)程正式在語言層面得到支持和優(yōu)化漾狼,大大簡化之前的yield寫法饥臂。線程是內(nèi)核進行搶占式的調(diào)度的,這樣就確保了每個線程都有執(zhí)行的機會稽煤。而 coroutine 運行在同一個線程中酵熙,由語言的運行時中的 EventLoop(事件循環(huán))來進行調(diào)度驰坊。和大多數(shù)語言一樣,在 Python 中拳芙,協(xié)程的調(diào)度是非搶占式的,也就是說一個協(xié)程必須主動讓出執(zhí)行機會,其他協(xié)程才有機會運行浆竭。讓出執(zhí)行的關(guān)鍵字就是 await。也就是說一個協(xié)程如果阻塞了删窒,持續(xù)不讓出 CPU顺囊,那么整個線程就卡住了,沒有任何并發(fā)诚亚。

PS: 作為服務(wù)端午乓,event loop最核心的就是IO多路復(fù)用技術(shù),所有來自客戶端的請求都由IO多路復(fù)用函數(shù)來處理;作為客戶端梢灭,event loop的核心在于利用Future對象延遲執(zhí)行蒸其,并使用send函數(shù)激發(fā)協(xié)程,掛起,等待服務(wù)端處理完成返回后再調(diào)用CallBack函數(shù)繼續(xù)下面的流程

Go的協(xié)程

Go天生在語言層面支持摸袁,和Python類似都是采用了關(guān)鍵字,而Go語言使用了go這個關(guān)鍵字耳鸯,可能是想表明協(xié)程是Go語言中最重要的特性膀曾。

go

協(xié)程之間的通信,Go采用了channel關(guān)鍵字财喳。

Go實現(xiàn)了兩種并發(fā)形式:

多線程共享內(nèi)存斩狱。如Java或者C++等在多線程中共享數(shù)據(jù)(例如數(shù)組所踊、Map、或者某個結(jié)構(gòu)體或?qū)ο螅┑臅r候碌燕,通過鎖來訪問.

Go語言特有的,也是Go語言推薦的:CSP(communicating sequential

? ? processes)并發(fā)模型愈捅。

Go的CSP并發(fā)模型實現(xiàn):M, P, G : [https://www.cnblogs.com/sunsk...]

package main


import (

??? "fmt"

)


//Go 協(xié)程(goroutines)和協(xié)程(coroutines)

//Go 協(xié)程意味著并行(或者可以以并行的方式部署)慈鸠,協(xié)程一般來說不是這樣的

//Go 協(xié)程通過通道來通信;協(xié)程通過讓出和恢復(fù)操作來通信


// 進程退出時不會等待并發(fā)任務(wù)結(jié)束譬巫,可用通道(channel)阻塞缕题,然后發(fā)出退出信號

func main() {

??? jobs := make(chan int)

??? done := make(chan bool) //結(jié)束標志


??? go func() {

??????? for {

??????????? j, more := <-jobs //? 利用more這個值來判斷通道是否關(guān)閉胖腾,如果關(guān)閉了,那么more的值為false锨阿,并且通知給通道done

??????????? fmt.Println("----->:",j, more)

??????????? if more {

??????????????? fmt.Println("receivedjob", j)

??????????? } else {

??????????????? fmt.Println("end receivedjobs")

??????????????? done <- true

??????????????? return

??????????? }

??????? }

??? }()


??? go func() {

??????? for j := 1; j <= 3; j++ {

??????????? jobs <- j

??????????? fmt.Println("sent job",j)

??????? }

??????? close(jobs) //寫完最后的數(shù)據(jù),緊接著就close掉

??????? fmt.Println("close(jobs)")

??? }()


??? fmt.Println("sent all jobs")

??? <-done //讓main等待全部協(xié)程完成工作

}


通過在函數(shù)調(diào)用前使用關(guān)鍵字 go墅诡,我們即可讓該函數(shù)以 goroutine 方式執(zhí)行末早。goroutine 是一種 比線程更加輕盈、更省資源的協(xié)程然磷。

Go

語言通過系統(tǒng)的線程來多路派遣這些函數(shù)的執(zhí)行姿搜,使得 每個用 go 關(guān)鍵字執(zhí)行的函數(shù)可以運行成為一個單位協(xié)程捆憎。當(dāng)一個協(xié)程阻塞的時候,調(diào)度器就會自 動把其他協(xié)程安排到另外的線程中去執(zhí)行致份,從而實現(xiàn)了程序無等待并行化運行知举。而且調(diào)度的開銷非常小瞬沦,一顆 CPU 調(diào)度的規(guī)模不下于每秒百萬次,這使得我們能夠創(chuàng)建大量的 goroutine僚焦,從而可以很輕松地編寫高并發(fā)程序芳悲,達到我們想要的目的。 ---- 某書

協(xié)程的4種狀態(tài)

Pending

Running

Done

Cacelled

和系統(tǒng)線程之間的映射關(guān)系

go的協(xié)程本質(zhì)上還是系統(tǒng)的線程調(diào)用谅年,而Python中的協(xié)程是eventloop模型實現(xiàn)肮韧,所以雖然都叫協(xié)程弄企,但并不是一個東西.

Python

中的協(xié)程是嚴格的 1:N 關(guān)系,也就是一個線程對應(yīng)了多個協(xié)程意乓。雖然可以實現(xiàn)異步I/O约素,但是不能有效利用多核(GIL)圣猎。而 Go 中是 M:N 的關(guān)系,也就是 N 個協(xié)程會映射分配到 M 個線程上为障,這樣帶來了兩點好處:

多個線程能分配到不同核心上,CPU 密集的應(yīng)用使用 goroutine 也會獲得加速.

即使有少量阻塞的操作放祟,也只會阻塞某個 worker 線程跪妥,而不會把整個程序阻塞。

PS: Go中很少提及線程或進程,也就是因為上面的原因.

兩種協(xié)程對比:

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

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

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

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

PS: python異步庫列表 [https://github.com/timofurrer...]

Do not communicate by sharing memory;

instead, share memory by communicating.(不要以共享內(nèi)存的方式來通信缴允,相反珍德,要通過通信來共享內(nèi)存) -- CSP并發(fā)模型

擴展與總結(jié)

erlang和golang都是采用了CSP(Communicating Sequential Processes)模式(Python中的協(xié)程是eventloop模型)

但是erlang是基于進程的消息通信,go是基于goroutine和channel的通信敞贡。

Python

和Go都引入了消息調(diào)度系統(tǒng)模型都办,來避免鎖的影響和進程/線程開銷大的問題。協(xié)程從本質(zhì)上來說是一種用戶態(tài)的線程,不需要系統(tǒng)來執(zhí)行搶占式調(diào)度歌懒,而是在語言層面實現(xiàn)線程的調(diào)度溯壶。因為協(xié)程不再使用共享內(nèi)存/數(shù)據(jù)且改,而是使用通信來共享內(nèi)存/鎖又跛,因為在一個超級大系統(tǒng)里具有無數(shù)的鎖慨蓝,共享變量等等會使得整個系統(tǒng)變得無比的臃腫,而通過消息機制來交流弧满,可以使得每個并發(fā)的單元都成為一個獨立的個體庭呜,擁有自己的變量犀忱,單元之間變量并不共享募谎,對于單元的輸入輸出只有消息。開發(fā)者只需要關(guān)心在一個并發(fā)單元的輸入與輸出的影響峡碉,而不需要再考慮類似于修改共享內(nèi)存/數(shù)據(jù)對其它程序的影響近哟。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鲫寄,隨后出現(xiàn)的幾起案子吉执,更是在濱河造成了極大的恐慌疯淫,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件戳玫,死亡現(xiàn)場離奇詭異熙掺,居然都是意外死亡,警方通過查閱死者的電腦和手機咕宿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門府阀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來董瞻,“玉大人,你說我怎么就攤上這事抄伍〗卣洌” “怎么了隧饼?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長僧免。 經(jīng)常有香客問我,道長牵敷,這世上最難降的妖魔是什么枷餐? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任润匙,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己逮诲,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般锭弊。 火紅的嫁衣襯著肌膚如雪味滞。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天,我揣著相機與錄音就轧,去河邊找鬼镇饺。 笑死惋啃,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播惰帽,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼垂涯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了操骡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年署穗,在試婚紗的時候發(fā)現(xiàn)自己被綠了褐啡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡糕档,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤汽久,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布苍碟,位于F島的核電站蜓肆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一习柠、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至藐守,卻和暖如春惠啄,著一層夾襖步出監(jiān)牢的瞬間死嗦,已是汗流浹背外盯。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容