nodejs和golang都是支持協程的,從表現上來看,nodejs對於協程的支持在於async/await,golang對協程的支持在於goroutine。關於協程的話題,簡單來講,能夠看做是非搶佔式的輕量級線程。前端
一句話歸納,上面提到了node
"能夠看做是非搶佔式的輕量級線程"。c++
在多線程中,把一段代碼放在一個線程中執行,cpu會自動將代碼分紅碎片,並在必定時間切換cpu控制權,線程經過鎖機制確保本身使用的資源在cpu執行別的線程的代碼時被修改(佔用的內存堆棧、硬盤數據資源等),也就是說經過鎖機制,golang
線程a在一塊內存中建立了一個變量,線程a代碼還沒結束,cpu切換去執行線程b了,可是因爲鎖,線程b沒法使用這塊內存。express
若是僅在單核單線程cpu下來看,多線程和多協程沒有任何區別,由於線程不能並行,只能是cpu分碎片執行。c#
協程就是相似這個意思。協程是線程內的東西(暫且不談多線程下的協程),當協程遇到阻塞時,就切換線程控制權,讓線程去執行另一個協程,只不過這個過程是排隊的。這和nodejs的事件輪詢是一回事,在nodejs中先告知系統我如今要promise
讀取文件了,系統讀取,io阻塞了,nodejs去執行下一段代碼B,執行完後檢查阻塞是否等待完畢,若是等待完畢就把結果推到事件隊列背後去執行回調函數。這一段話我用協程的意思來表達一下,把讀取文件,讀取結束後執行相應操做放在一個協程a服務器
內,執行代碼B放在一個協程b內,線程執行協程a,a遇到io阻塞了,切換線程控制權,執行協程b,b執行結束,切換線程控制權,執行協程a。對於js用戶來講,協程是回調的另外一種表現形式。多線程
function sleep(ms){koa
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上運行其餘碾壓其餘全部對手