關於協程 nodejs和golang協程的不同

2022-07-14 14:39:20 字數 2874 閱讀 4381

nodejs和golang都是支援協程的,從表現上來看,nodejs對於協程的支援在於async/await,golang對協程的支援在於goroutine。關於協程的話題,簡單來說,可以看作是非搶占式的輕量級執行緒。

一句話概括,上面提到了

"可以看作是非搶占式的輕量級執行緒"。

在多執行緒中,把一段**放在乙個執行緒中執行,cpu會自動將**分成碎片,並在一定時間切換cpu控制權,執行緒通過鎖機制確保自己使用的資源在cpu執行別的執行緒的**時被修改(占用的記憶體堆疊、硬碟資料資源等),也就是說通過鎖機制,

執行緒a在一塊記憶體中建立了乙個變數,執行緒a**還沒結束,cpu切換去執行執行緒b了,但是由於鎖,執行緒b無法使用這塊記憶體。

如果僅在單核單執行緒cpu下來看,多執行緒和多協程沒有任何區別,因為執行緒不能並行,只能是cpu分碎片執行。

協程就是類似這個意思。協程是執行緒內的東西(暫且不談多執行緒下的協程),當協程遇到阻塞時,就切換執行緒控制權,讓執行緒去執行另外乙個協程,只不過這個過程是排隊的。這和nodejs的事件輪詢是一回事,在nodejs中先告知系統我現在要

讀取檔案了,系統讀取,io阻塞了,nodejs去執行下一段**b,執行完後檢查阻塞是否等待完畢,如果等待完畢就把結果推到事件佇列背後去執行**函式。這一段話我用協程的意思來表達一下,把讀取檔案,讀取結束後執行相應操作放在乙個協程a

內,執行**b放在乙個協程b內,執行緒執行協程a,a遇到io阻塞了,切換執行緒控制權,執行協程b,b執行結束,切換執行緒控制權,執行協程a。對於js使用者來說,協程是**的另一種表現形式。

function sleep(ms){

return new promise((resolve,reject)=>settimeout(

()=>resolve(),ms

))(async function (){

await sleep(3000)

console.log("你好")

(async function (){

await sleep(3000)

console.log("世界")

可以這麼看,執行async函式就是執行一段協程**,await關鍵字就是切換協程,在await後就去執行其他協程的**了。

func deferprint(str string){

time.sleep(time.second*2)

fmt.println(str)

func main(){

go deferprint("你好")

go deferprint("世界")

//如果主協程不阻塞,永遠不會切換

time.sleep(time.seconds*2)

golang的go關鍵字就是將一段**放在乙個協程裡,執行緒選擇協程執行,碰見阻塞就自動切換協程執行,但需要注意的是,golang不會因為乙個協程執行結束就自動切換,必須是阻塞之後

golang的協程是可以帶鎖的 lock.mutex() unlock(),nodejs是號稱永遠不會死鎖也根本沒有鎖這回事。

沒有鎖會導致的問題在於占用的資源被輕易修改

比如讀取乙個檔案,如果該檔案為0kb我就寫乙個字串進去,如果大於0kb,我就不執行任何操作。協程中會有兩次阻塞,第一次是讀取該檔案,判斷檔案大小,第二次是寫入。假如有兩個函式簽名如下

async function getfilesize(filename) : number

async function writefile(data,filename) :bool

async function exec(){

size = await getfilesize("./test.txt");

if(size==0){

await writefile("你好","./test.txt")

console.log("ok!")

如果我第一次判斷結束後另乙個協程裡執行了插入操作,那麼幾個函式的執行順序就會變成

a: getfilesize()檢查檔案大小,協程阻塞,切換協程

b: 寫入檔案,協程阻塞,切換協程

a: getfilesize()檢查文字大小結束,可以插入,執行writefile()

但是此時佇列中還有乙個b協程的插入操作會在a之前執行,a協程對此不知道,以為檔案還是0kb

如果檔案被上鎖了

a: getfilesize()檢查檔案大小,協程阻塞,切換協程

b: 寫入檔案,哦——協程a鎖住了這個檔案,那我等他釋放把,切換協程

a: getfilesize()完成,插入操作

b: 哦——協程a還在占用,那我接著等

a: 搞定了,釋放鎖,我已經沒有什麼要執行的了,把我從佇列裡刪掉吧

b: 協程a釋放了檔案的鎖,現在我可以寫入了

golang之所以要支援鎖協程,我想是為了多執行緒支援。golang中可以啟用多個執行緒並行執行相同數量的協程。

nodejs受限於v8的isolate機制,只能跑在單執行緒中。所有**無法並行執行,無法處理計算密集型應用場景。

nodejs使用await阻塞協程,手動切換執行緒控制權,node的協程是c++控制的,c++裡寫了這個函式可以被推入事件佇列就能夠用promise封裝成協程

golang在協程阻塞時自動切換協程,所以在寫golang的時候所有的**可以都寫同步**,然後用go關鍵字去呼叫,golang的協程是自己規定的,所有

函式在阻塞時都必須切換執行緒控制權

nodejs中async函式是能直接返回值的

golang只能傳遞乙個引用的channel

總的來說golang和nodejs應用場景不同。nodejs適合前端鼓搗,用plug/ejs配合express/koa2從伺服器http請求資料後再填到模版引擎裡

golang類似與小c++,最大的亮點就是使用協程管理多執行緒

對語言來說,不應該選邊站,但還是捧一波c#,除了只能在.net上執行其他碾壓其他所有對手

關於協程的 send None

這段時間太忙了,沒時間更新部落格。今天把python撿起來,看了下 協程。記錄乙個一開始沒太明白的點。直接貼 def consumer r j 0 while true n yield r 3 j j 1 print j d j if not n return print consumer cons...

協程和恢復

乙個用到recover的程式停掉伺服器內部乙個失敗的協程而不影響其他協程的工作。func server workchan chan work func safelydo work work do work do work 發生panic,錯誤會被記錄且協程會退出釋放,其他協程不受影響 因為recov...

關於協程的問題總結

協程其實就是可以由程式自主控制的執行緒 在python裡主要由yield 和yield from 控制,可以通過生成者消費者例子來理解協程 利用yield from 向生成器 協程 傳送資料 傳統的生產者 消費者是乙個執行緒寫訊息,乙個執行緒取訊息,通過鎖機制控制佇列和等待,但一不小心就可能死鎖。如...