前文中中咱們用實驗的方式驗證了Linux進程和線程的上下文切換開銷,大約是3-5us之間。當運行在通常的計算機程序時,這個開銷確實不算大。可是海量互聯網服務端和通常的計算機程序相比,特色是:php
即便3-5us的開銷,若是上下文切換量特別大的話,也仍然會顯得是有那麼一些性能低下。例如以前的Web Server之Apache,就是這種模型下的軟件產品。(其實當時Linux操做系統在設計的時候,目標是一個通用的操做系統,並非專門針對服務端高併發來設計的)程序員
爲了不頻繁的上下文切換,還有一種異步非阻塞的開發模型。那就是用一個進程或線程去接收一大堆用戶的請求,而後經過IO多路複用的方式來提升性能(進程或線程不阻塞,省去了上下文切換的開銷)。Nginx和Node Js就是這種模型的典型表明產品。平心而論,從程序運行效率上來,這種模型最爲機器友好,運行效率是最高的(比下面提到的協程開發模型要好)。因此Nginx已經取代了Apache成爲了Web Server裏的首選。可是這種編程模型的問題在於開發不友好,說白了就是過於機器化,離進程概念被抽象出來的初衷背道而馳。人類正常的線性思惟被打亂,應用層開發們被逼得以非人類的思惟去編寫代碼,代碼調試也變得異常困難。redis
因而就有一些聰明的腦殼們繼續在應用層又動起了主意,設計出了不須要進程/線程上下文切換的「線程」,協程。用協程去處理高併發的應用場景,既可以符合進程涉及的初衷,讓開發者們用人類正常的線性的思惟去處理本身的業務,也一樣可以省去昂貴的進程/線程上下文切換的開銷。所以能夠說,協程就是Linux處理海量請求應用場景裏的進程模型的一個很好的的補丁。sql
背景介紹完了,那麼我想說的是,畢竟協程的封裝雖然輕量,可是畢竟仍是須要引入了一些額外的代價的。那麼咱們來看看這些額外的代價具體多小吧。編程
測試代碼以下,測試過程是不斷在協程之間讓出CPU。核心代碼以下:後端
func cal() { for i :=0 ; i<1000000 ;i++{ runtime.Gosched() } } func main() { runtime.GOMAXPROCS(1) currentTime:=time.Now() fmt.Println(currentTime) go cal() for i :=0 ; i<1000000 ;i++{ runtime.Gosched() } currentTime=time.Now() fmt.Println(currentTime) }
好了,讓咱們編譯運行一下:緩存
# cd tests/test05/src/main/; # go build # ./main 2019-08-08 22:35:13.415197171 +0800 CST m=+0.000286059 2019-08-08 22:35:13.655035993 +0800 CST m=+0.240124923
平均每次協程切換的開銷是(655035993-415197171)/2000000=120ns。相對於前面文章測得的進程切換開銷大約3.5us,大約是其的三十分之一。比系統調用的形成的開銷還要低。網絡
在空間上,協程初始化建立的時候爲其分配的棧有2KB。而線程棧要比這個數字大的多,能夠經過ulimit 命令查看,通常都在幾兆,做者的機器上是10M。若是對每一個用戶建立一個協程去處理,100萬併發用戶請求只須要2G內存就夠了,而若是用線程模型則須要10T。併發
# ulimit -a stack size (kbytes, -s) 10240
協程因爲是在用戶態來完成上下文切換的,因此切換耗時只有區區100ns多一些,比進程切換要高30倍。單個協程須要的棧內存也足夠小,只須要2KB。因此,近幾年來協程大火,在互聯網後端的高併發場景裏大放光彩。異步
不管是空間仍是時間性能都比進程(線程)好這麼多,那麼Linus爲啥不把它在操做系統裏實現了多好?
實際上協程並非一個新玩意,在上個世紀60年代的時候就已經有人提出了。操做系統的一個主要設計目標是實時性,對優先級比較高的進程是會搶佔當前佔用CPU的進程。可是協程沒法實現這一點,還得依賴於使用CPU的一方主動釋放,與操做系統的實現目的不相吻合。協程的高效是以犧牲了可搶佔性爲代價的。
擴展:因爲go的協程調用起來太方便了,因此一些go的程序員就很隨意地go來go去。要知道go這條指令在切換到協程以前,得先把協程建立出來。而一次建立加上調度開銷就漲到400ns,差很少至關於一次系統調用的耗時了。雖然協程很高效,可是也不要亂用,不然go祖師爺Rob Pike花大精力優化出來的性能,被你隨意一go又給葬送掉了。
開發內功修煉之CPU篇專輯:
個人公衆號是「開發內功修煉」,在這裏我不是單純介紹技術理論,也不僅介紹實踐經驗。而是把理論與實踐結合起來,用實踐加深對理論的理解、用理論提升你的技術實踐能力。歡迎你來關注個人公衆號,也請分享給你的好友~~~