從調度上看,goroutine的調度開銷遠遠小於線程調度開銷。程序員
OS的線程由OS內核調度,每隔幾毫秒,一個硬件時鐘中斷髮到CPU,CPU調用一個調度器內核函數。這個函數暫停當前正在運行的線程,把他的寄存器信息保存到內存中,查看線程列表並決定接下來運行哪個線程,再從內存中恢復線程的註冊表信息,最後繼續執行選中的線程。這種線程切換須要一個完整的上下文切換:即保存一個線程的狀態到內存,再恢復另一個線程的狀態,最後更新調度器的數據結構。某種意義上,這種操做仍是很慢的。編程
Go運行的時候包涵一個本身的調度器,這個調度器使用一個稱爲一個M:N調度技術,m個goroutine到n個os線程(能夠用GOMAXPROCS來控制n的數量),Go的調度器不是由硬件時鐘來按期觸發的,而是由特定的go語言結構來觸發的,他不須要切換到內核語境,因此調度一個goroutine比調度一個線程的成本低不少。數據結構
從棧空間上,goroutine的棧空間更加動態靈活。多線程
每一個OS的線程都有一個固定大小的棧內存,一般是2MB,棧內存用於保存在其餘函數調用期間哪些正在執行或者臨時暫停的函數的局部變量。這個固定的棧大小,若是對於goroutine來講,多是一種巨大的浪費。做爲對比goroutine在生命週期開始只有一個很小的棧,典型狀況是2KB, 在go程序中,一次建立十萬左右的goroutine也不罕見(2KB*100,000=200MB)。並且goroutine的棧不是固定大小,它能夠按需增大和縮小,最大限制能夠到1GB。編程語言
goroutine沒有一個特定的標識。函數
在大部分支持多線程的操做系統和編程語言中,線程有一個獨特的標識,一般是一個整數或者指針,這個特性可讓咱們構建一個線程的局部存儲,本質是一個全局的map,以線程的標識做爲鍵,這樣每一個線程能夠獨立使用這個map存儲和獲取值,不受其餘線程干擾。操作系統
goroutine中沒有可供程序員訪問的標識,緣由是一種純函數的理念,不但願濫用線程局部存儲致使一個不健康的超距做用,即函數的行爲不只取決於它的參數,還取決於運行它的線程標識。線程
reference: 《Go程序設計語言》設計