多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內最全IT社區平臺 聯系我們 | 收藏本站
阿里云優惠2
您當前位置:首頁 > php開源 > php教程 > golang技術隨筆(二)理解goroutine

golang技術隨筆(二)理解goroutine

來源:程序員人生   發布時間:2015-03-31 08:09:47 閱讀次數:4718次

進程、線程和協程

要理解甚么是goroutine,我們先來看看進程、線程和協程它們之間的區分,這能幫助我們更好的理解goroutine。

進程:分配完全獨立的地址空間,具有自己獨立的堆和棧,既不同享堆,亦不同享棧,進程的切換只產生在內核態,由操作系統調度。
線程:和其它本進程的線程同享地址空間,具有自己獨立的棧和同享的堆,同享堆,不同享棧,線程的切換1般也由操作系統調度(標準線程是的)。
協程:和線程類似,同享堆,不同享棧,協程的切換1般由程序員在代碼中顯式控制。

進程和線程的切換主要依賴于時間片的控制(關于進程和線程的調度方式,具體可參看這篇文章:http://blog.chinaunix.net/uid⑵0476365-id⑴942505.html),而協程的切換則主要依賴于本身,這樣的好處是避免了無意義的調度,由此可以提高性能,但也因此,程序員必須自己承當調度的責任。

goroutine可以看做是協程的go語言實現,從百度百科上看協程的定義:與子例程1樣,協程(coroutine)也是1種程序組件。相對子例程而言,協程更加1般和靈活,但在實踐中使用沒有子例程那樣廣泛。實際上,我們可以把子例程當作是協程的1種特例。1般來講,如果沒有顯式的讓出CPU,就會1直履行當前協程。

淺析goroutine

我們知道goroutine是協程的go語言實現,它是語言原生支持的,相對1般由庫實現協程的方式,goroutine更加強大,它的調度1定程度上是由go運行時(runtime)管理。其好處之1是,當某goroutine產生阻塞時(例猶如步IO操作等),會自動出讓CPU給其它goroutine。

goroutine的使用非常簡單,例如foo是1個函數:

go foo()

就1個關鍵字go弄定了,這里會啟動1個goroutine履行foo函數,然后CPU繼續履行后面的代碼。這里雖然啟動了goroutine,但其實不意味著它會得到馬上調度,關于goroutine的調度我們稍后再探討。

goroutine是非常輕量級的,它就是1段代碼,1個函數入口,和在堆上為其分配的1個堆棧(初始大小為4K,會隨著程序的履行自動增長刪除)。所以它非常便宜,我們可以很輕松的創建上萬個goroutine。

go運行時調度

默許的, 所有goroutine會在1個原生線程里跑,也就是只使用了1個CPU核。在同1個原生線程里,如果當前goroutine不產生阻塞,它是不會讓出CPU時間給其他同線程的goroutines的。除被系統調用阻塞的線程外,Go運行庫最多會啟動$GOMAXPROCS個線程來運行goroutine。

那末goroutine究竟是如何被調度的呢?我們從go程序啟動開始說起。在go程序啟動時會首先創建1個特殊的內核線程sysmon,從名字就能夠看出來它的職責是負責監控的,goroutine背后的調度可以說就是靠它來弄定。

接下來,我們再看看它的調度模型,go語言當前的實現是N:M。即1定數量的用戶線程映照到1定數量的OS線程上,這里的用戶線程在go中指的就是goroutine。go語言的調度模型需要弄清楚3個概念:M、P和G,以下圖表示:
這里寫圖片描述
M代表OS線程,G代表goroutine,P的概念比較重要,它表示履行的上下文,其數量由$GOMAXPROCS決定,1般來講正好等于處理器的數量。M必須和P綁定才能履行G,調度器需要保證所有的P都有G履行,以保證并行度。以下圖:
這里寫圖片描述
從圖中我們可以看見,當前有兩個P,各自綁定了1個M,并分別履行了1個goroutine,我們還可以看見每一個P上還掛了1個G的隊列,這個隊列是代表私有的任務隊列,它們實際上都是runnable狀態的goroutine。當使用go關鍵字聲明時,1個goroutine便被加入到運行隊列的尾部。1旦1個goroutine運行到1個調度點,上下文便從運行隊列中取出1個goroutine, 設置好棧和指令指針,便開始運行新的goroutine。

那末go中切換goroutine的調度點有哪些呢?具體有以下3種情況

  • 調用runtime?gosched函數。goroutine主動放棄CPU,該goroutine會被設置為runnable狀態,然后放入1個全局等待隊列中,而P將繼續履行下1個goroutine。使用runtime?gosched函數是1個主動的行動,1般是在履行長任務時又想其它goroutine得到履行的機會時調用。
  • 調用runtime?park函數。goroutine進入waitting狀態,除非對其調用runtime?ready函數,否則該goroutine將永久不會得到履行。而P將繼續履行下1個goroutine。使用runtime?park函數1般是在某個條件如果得不到滿足就不能繼續運行下去時調用,當條件滿足后需要使用runtime?ready以喚醒它(這里喚醒以后是不是會加入全局等待隊列還有待研究)。像channel操作,定時器中,網絡poll等都有可能park goroutine。
  • 慢系統調用。這樣的系統調用會阻塞等待,為了使該P上掛著的其它G也能得到履行的機會,需要將這些goroutine轉到另外一個OS線程上去。具體的做法是:首先將該P設置為syscall狀態,然后該線程進入系統調用阻塞等待。之條件到過的sysmom線程會定期掃描所有的P,發現1個P處于了syscall的狀態,就將M和P分離(實際上只有當 Syscall 履行時間超越某個閾值時,才會將 M 與 P 分離)。RUNTIME會再分配1個M和這個P綁定,從而繼續履行隊列中的其它G。而當之前阻塞的M從系統調用中返回后,會將該goroutine放入全局等待隊列中,自己則sleep去。
    這里寫圖片描述
    該圖描寫了M和P的分離進程。

調度點的情況說清楚了,但全部模型還其實不完全。我們知道當使用go去調用1個函數,會生成1個新的goroutine放入當前P的隊列中,那末甚么時候生成別的OS線程,各個OS線程又是如何做負載均衡的呢?

當M從隊列中拿到1個可履行的G后,首先會去檢查1下,自己的隊列中是不是還有等待的G,如果還有等待的G,并且也還有空閑的P,此時就會通知runtime分配1個新的M(如果有在睡覺的OS線程,則直接喚醒它,沒有的話則生成1個新的OS線程)來分擔負務。

如果某個M發現隊列為空以后,會首先從全局隊列中取1個G來處理。如果全局隊列也空了,則會隨機從別的P那里直接截取1半的隊列過來(偷竊任務),如果發現所有的P都沒有可供偷竊的G了,該M就會墮入沉睡。

全部調度模型大致就是這模樣了,和所有協程的調度1樣,在響應時間上,這類協作式調度是硬傷。很容易致使某個協程長時間沒法得到履行。但整體來講,它帶來的好處更加讓人驚嘆。想要了解的更多可以看看我下面列出的1些參考資料,或是直接看它的源碼:http://golang.org/src/runtime/proc.c

總綱傳送門:golang技術隨筆總綱

參考資料

  1. 協程
  2. goroutine背后的系統知識
  3. The Go scheduler
  4. goroutine與調度器
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關閉
程序員人生
主站蜘蛛池模板: 欧美亚洲国产精品久久第一页 | 国产精品久久久久久久久久一区 | 日韩欧美视频在线 | 最新中文字幕在线 | 一级毛毛片毛片毛片毛片在线看 | 亚洲视频 在线观看 | 欧美黑粗特黄午夜大片 | 久久精品免费全国观看国产 | 日韩欧美国产一区二区三区四区 | 一二三四视频在线6 1免费观看 | 国产欧美日韩图片一区二区 | 国产精品爱久久久久久久9999 | 国内自拍 亚洲系列 欧美系列 | 国产精品一区二区不卡 | 综合天堂| 亚洲吹箫 | 国产精品永久免费视频 | 免费看黄大全 | 亚洲成人一区在线 | 国产日韩亚洲欧洲一区二区三区 | 亚洲精品自产拍在线观看 | 日本理论午夜中文字幕第一页 | 男女男精品视频网站在线观看 | 日韩在线不卡一区在线观看 | 亚洲天堂视频在线观看 | 日韩国产精品99久久久久久 | 欧美一区二 | 久爱精品| 国产图色 | 亚洲一区二区久久 | 在线视频欧美精品 | fxxxx性欧美高清 | 亚洲国产片在线观看 | 沈樵在线观看福利 | 亚洲乱码卡三乱码新区 | 日韩高清一区二区 | 国产一区二区三区四区 | 亚洲精品视频久久久 | 日本中文在线播放 | 中文字幕人成乱码在线观看 | 波多野结衣一区二区三区四区 |