您好,登錄后才能下訂單哦!
這篇文章給大家介紹協程在go與python中的區別有哪些,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。
進程、線程和協程
進程的定義:
進程,是計算機中已運行程序的實體。程序本身只是指令、數據及其組織形式的描述,進程才是程序的真正運行實例。
線程的定義:
操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。
進程和線程的關系:
一條線程指的是進程中一個單一順序的控制流,一個進程中可以并發多個線程,每條線程并行執行不同的任務。
CPU的最小調度單元是線程不是進程,所以單進程多線程也可以利用多核CPU.
協程的定義:
協程通過在線程中實現調度,避免了陷入內核級別的上下文切換造成的性能損失,進而突破了線程在IO上的性能瓶頸。
協程和線程的關系
協程是在語言層面實現對線程的調度,避免了內核級別的上下文消耗。
python協程與調度
Python的協程源于yield指令。yield有兩個功能:
?yield item用于產出一個值,反饋給next()的調用方。
?作出讓步,暫停執行生成器,讓調用方繼續工作,直到需要使用另一個值時再調用next()。
import asyncio import datetime async def display_date(): loop = asyncio.get_running_loop() end_time = loop.time() + 5.0 while True: print(datetime.datetime.now()) if (loop.time() + 1.0) >= end_time: break await asyncio.sleep(1) asyncio.run(display_date())
協程是對線程的調度,yield類似惰性求值方式可以視為一種流程控制工具,實現協作式多任務,在Python3.5正式引入了 Async/Await表達式,使得協程正式在語言層面得到支持和優化,大大簡化之前的yield寫法。
線程是內核進行搶占式的調度的,這樣就確保了每個線程都有執行的機會。
而 coroutine 運行在同一個線程中,由語言的運行時中的 EventLoop(事件循環)來進行調度。
和大多數語言一樣,在 Python 中,協程的調度是非搶占式的,也就是說一個協程必須主動讓出執行機會,其他協程才有機會運行。
讓出執行的關鍵字就是 await。也就是說一個協程如果阻塞了,持續不讓出 CPU,那么整個線程就卡住了,沒有任何并發。
PS: 作為服務端,event loop最核心的就是IO多路復用技術,所有來自客戶端的請求都由IO多路復用函數來處理;作為客戶端,
event loop的核心在于利用Future對象延遲執行,并使用send函數激發協程,掛起,等待服務端處理完成返回后再調用CallBack函數繼續下面的流程
Go的協程是天生在語言層面支持,和Python類似都是采用了關鍵字,而Go語言使用了go這個關鍵字,可能是想表明協程是Go語言中最重要的特性。
go協程之間的通信,Go采用了channel關鍵字。
Go實現了兩種并發形式:
?多線程共享內存。如Java或者C++等在多線程中共享數據(例如數組、Map、或者某個結構體或對象)的時候,通過鎖來訪問.
?Go語言特有的,也是Go語言推薦的:CSP(communicating sequential processes)并發模型。
Go的CSP并發模型實現:M, P, G :
package main import ( "fmt" ) //Go 協程(goroutines)和協程(coroutines) //Go 協程意味著并行(或者可以以并行的方式部署),協程一般來說不是這樣的 //Go 協程通過通道來通信;協程通過讓出和恢復操作來通信 // 進程退出時不會等待并發任務結束,可用通道(channel)阻塞,然后發出退出信號 func main() { jobs := make(chan int) done := make(chan bool) // 結束標志 go func() { for { j, more := <-jobs // 利用more這個值來判斷通道是否關閉,如果關閉了,那么more的值為false,并且通知給通道done fmt.Println("----->:", j, more) if more { fmt.Println("received job", j) } else { fmt.Println("end received jobs") done <- true return } } }() go func() { for j := 1; j <= 3; j++ { jobs <- j fmt.Println("sent job", j) } close(jobs) // 寫完最后的數據,緊接著就close掉 fmt.Println("close(jobs)") }() fmt.Println("sent all jobs") <-done // 讓main等待全部協程完成工作 }
通過在函數調用前使用關鍵字 go,我們即可讓該函數以 goroutine 方式執行。goroutine 是一種 比線程更加輕盈、更省資源的協程。
Go 語言通過系統的線程來多路派遣這些函數的執行,使得 每個用 go 關鍵字執行的函數可以運行成為一個單位協程。
當一個協程阻塞的時候,調度器就會自 動把其他協程安排到另外的線程中去執行,從而實現了程序無等待并行化運行。
而且調度的開銷非常小,一顆 CPU 調度的規模不下于每秒百萬次,這使得我們能夠創建大量的 goroutine,
從而可以很輕松地編寫高并發程序,達到我們想要的目的。 ---- 某書
協程的4種狀態
?Pending
?Running
?Done
?Cacelled
和系統線程之間的映射關系
go的協程本質上還是系統的線程調用,而Python中的協程是eventloop模型實現,所以雖然都叫協程,但并不是一個東西.
Python 中的協程是嚴格的 1:N 關系,也就是一個線程對應了多個協程。雖然可以實現異步I/O,但是不能有效利用多核(GIL)。
而 Go 中是 M:N 的關系,也就是 N 個協程會映射分配到 M 個線程上,這樣帶來了兩點好處:
?多個線程能分配到不同核心上,CPU 密集的應用使用 goroutine 也會獲得加速.
?即使有少量阻塞的操作,也只會阻塞某個 worker 線程,而不會把整個程序阻塞。
PS: Go中很少提及線程或進程,也就是因為上面的原因.
兩種協程對比:
?async是非搶占式的,一旦開始采用 async 函數,那么你整個程序都必須是 async 的,不然總會有阻塞的地方(一遇阻塞對于沒有實現異步特性的庫就無法主動讓調度器調度其他協程了),也就是說 async 具有傳染性。
?Python 整個異步編程生態的問題,之前標準庫和各種第三方庫的阻塞性函數都不能用了,requests 不能用了,redis.py 不能用了,甚至 open 函數都不能用了。所以 Python 協程的最大問題不是不好用,而是生態環境不好。
?goroutine 是 go 與生俱來的特性,所以幾乎所有庫都是可以直接用的,避免了 Python 中需要把所有庫重寫一遍的問題。
?Goroutine 中不需要顯式使用 await 交出控制權,但是 Go 也不會嚴格按照時間片去調度 goroutine,而是會在可能阻塞的地方插入調度。Goroutine 的調度可以看做是半搶占式的。
PS: python異步庫列表 [https://github.com/timofurrer/awesome-asyncio]
--------------------------------------------------------------------------------
Do not communicate by sharing memory; instead, share memory by communicating.(不要以共享內存的方式來通信,相反,要通過通信來共享內存) -- CSP并發模型
--------------------------------------------------------------------------------
擴展與總結
erlang和golang都是采用了CSP(Communicating Sequential Processes)模式(Python中的協程是eventloop模型)
但是erlang是基于進程的消息通信,go是基于goroutine和channel的通信。
Python和Go都引入了消息調度系統模型,來避免鎖的影響和進程/線程開銷大的問題。
協程從本質上來說是一種用戶態的線程,不需要系統來執行搶占式調度,而是在語言層面實現線程的調度。
因為協程不再使用共享內存/數據,而是使用通信來共享內存/鎖,因為在一個超級大系統里具有無數的鎖,
共享變量等等會使得整個系統變得無比的臃腫,而通過消息機制來交流,可以使得每個并發的單元都成為一個獨立的個體,
擁有自己的變量,單元之間變量并不共享,對于單元的輸入輸出只有消息。
關于協程在go與python中的區別有哪些就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。