摘要:它避免了上下文切換的額外耗費,兼顧了多線程的優點,簡化了高并發程序的復雜。而可以理解為一種語言的協程。線程輕量級進程,,是程序執行流的最小單元。一個標準的線程由線程,當前指令指針,寄存器集合和堆棧組成。其實就是或者等語言中的多線程開發。
grape
全部視頻:https://segmentfault.com/a/11...
原視頻地址:https://biglive.xueersi.com/L...
GO協程有關知識(擴展)Go語言最大的特色就是從語言層面支持并發(Goroutine),Goroutine是Go中最基本的執行單元。事實上每一個Go程序至少有一個Goroutine:主Goroutine。當程序啟動時,它會自動創建。
首先了解什么是協程,什么是線程
協程:又稱微線程與子例程(或者稱為函數)一樣,協程(coroutine)也是一種程序組件。相對子例程而言,協程更為一般和靈活,但在實踐中使用沒有子例程那樣廣泛。和線程類似,共享堆,不共享棧,協程的切換一般由程序員在代碼中顯式控制。它避免了上下文切換的額外耗費,兼顧了多線程的優點,簡化了高并發程序的復雜。而Goroutine可以理解為一種Go語言的協程。同時它可以運行在一個或多個線程上。
線程:輕量級進程(Lightweight Process,LWP),是程序執行流的最小單元。一個標準的線程由線程ID,當前指令指針(PC),寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程自己不擁有系統資源,只擁有一點兒在運行中必不可少的資源,但它可與同屬一個進程的其它線程共享進程所擁有的全部資源。線程擁有自己獨立的棧和共享的堆,共享堆,不共享棧,線程的切換一般也由操作系統調度。
區別:協程是運行在線程上的,在代碼中顯示控制,沒有上下文切換所消耗的資源,協程擁有棧空間來存儲自己的上下文,如果棧空間不足,則會更改其他的協程。
Go實現了兩種并發形式。第一種是大家普遍認知的:多線程共享內存。其實就是Java或者C++等語言中的多線程開發。另外一種是Go語言特有的,也是Go語言推薦的:CSP(communicating sequential processes)并發模型。
CSP并發模型:以通信的方式來共享內存,傳統的多線程之間以共享內存來進行通信,GO語言則以通信的方式來共享內存,那么就來說一說這個CSP模型,它是通過goroutine和channel來實現的。
- goroutine 是Go語言中并發的執行單位。有點抽象,其實就是和傳統概念上的”線程“類似,可以理解為”線程“。 - channel是Go語言中各個并發結構體(goroutine)之前的通信機制。 通俗的講,就是各個goroutine之間通信的”管道“,有點類似于Linux中的管道。
生成一個goroutine需要代碼簡簡單單的go func()就可以生成,channel也是需要聲明chan即可,同時,channel在使用時需要注意,在讀和寫的時候channel都是堵塞的,向管道里寫或者讀數據類似于流輸入輸出。
GO并發的實現原理我們先從線程講起,無論語言層面何種并發模型,到了操作系統層面,一定是以線程的形態存在的。而操作系統根據資源訪問權限的不同,體系架構可分為用戶空間和內核空間;內核空間主要操作訪問CPU資源、I/O資源、內存資源等硬件資源,為上層應用程序提供最基本的基礎資源,用戶空間呢就是上層應用程序的固定活動空間,用戶空間不可以直接訪問資源,必須通過“系統調用”、“庫函數”或“Shell腳本”來調用內核空間提供的資源。
我們現在的計算機語言,可以狹義的認為是一種“軟件”,它們中所謂的“線程”,往往是用戶態的線程,和操作系統本身內核態的線程(簡稱KSE),還是有區別的。也就是說無論你怎么去實現并發,其實根本上都是去調用內核態的線程,一切并發都是紙老虎~
線程模型的實現,可以分為以下幾種方式:1.用戶級線程模型,2.內核級線程模型,3.兩級線程模型。而我們的GO線程模型就是一種特殊的兩級線程模型(GPM調度模型)。
GPM調度模型:G: 表示goroutine,存儲了goroutine的執行stack信息、goroutine狀態以及goroutine的任務函數等;
P: 表示邏輯processor,P的數量決定了系統內最大可并行的G的數量(前提:系統的物理cpu核數>=P的數量);P的最大作用還是其擁有的各種G對象隊列、鏈表、一些cache和狀態。
M: M代表著真正的執行計算資源。在綁定有效的p后,進入schedule循環;而schedule循環的機制大致是從各種隊列、p的本地隊列中獲取G,切換到G的執行棧上并執行G的函數,調用goexit做清理工作并回到m,如此反復。M并不保留G狀態,這是G可以跨M調度的基礎。
P是一個“邏輯Proccessor”,每個G要想真正運行起來,首先需要被分配一個P(進入到P的local runq中,這里暫忽略global runq那個環節)。對于G來說,P就是運行它的“CPU”,可以說:G的眼里只有P。但從Go scheduler視角來看,真正的“CPU”是M,只有將P和M綁定才能讓P的runq中G得以真實運行起來。
G-P-M模型的實現算是Go scheduler的一大進步,但Scheduler仍然有一個頭疼的問題,那就是不支持搶占式調度,導致一旦某個G中出現死循環或永久循環的代碼邏輯,那么G將永久占用分配給它的P和M,位于同一個P中的其他G將得不到調度,出現“餓死”的情況。更為嚴重的是,當只有一個P時(GOMAXPROCS=1)時,整個Go程序中的其他G都將“餓死”。那怎么辦呢?在GO1.2中,他增加了一個監控,Go程序啟動時,runtime會去啟動一個名為sysmon的m(一般稱為監控線程),該m無需綁定p即可運行,該m在整個Go程序的運行過程中至關重要:向長時間運行的G任務發出搶占調度,收回因syscall長時間阻塞的P等等
如果G被阻塞在某個system call操作上,那么不光G會阻塞,執行該G的M也會解綁P(實質是被sysmon搶走了),與G一起進入sleep狀態。如果此時有idle的M,則P與其綁定繼續執行其他G;如果沒有idle M,但仍然有其他G要去執行,那么就會創建一個新M。
參考文章:https://segmentfault.com/a/11...
https://blog.csdn.net/weixin_...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/31428.html
摘要:原文鏈接原文作者今天譯者注年月日是版本的發布日,同時會對協程的結構化并發做一些介紹。進一步的閱讀結構化并發的概念背后有更多的哲學。現代語言開始為我們提供一種以完全非結構化啟動并發任務的方式,這玩意該結束了。 原文鏈接:Structured concurrency 原文作者:Roman Elizarov 今天(譯者注:18年9月12日) 是 kotlinx.coroutines 0.26...
摘要:開發負責人創建分支,編寫單元測試腳本,編寫代碼,實現提案中的所有內容,最終發起交叉評審,檢查代碼,提出改進意見,反饋給開發負責人,繼續完善細節。 Swoole開源項目從2012年開始發布第一個版本,到現在已經有近7年的歷史。在這七年的時間里: 提交了8821次代碼變更 發布了287個版本 收到并解決1161次issue反饋 合并了603次pull request 共有100位開發者...
摘要:為語言提供了強大的協程編程模式。提供的協程語法借鑒自,在此向開發組致敬協程可以與很好地互補。并發執行使用創建協程,可以讓和兩個函數變成并發執行。協程需要拿到請求的結果。 Swoole4為PHP語言提供了強大的CSP協程編程模式。底層提供了3個關鍵詞,可以方便地實現各類功能。 Swoole4提供的PHP協程語法借鑒自Golang,在此向GO開發組致敬 PHP+Swoole協程可以與...
摘要:關鍵字表示代碼在該處將會被阻塞式暫停阻塞的僅僅是函數代碼本身,而不是整個程序,但是這并沒有引起函數內部自頂向下代碼的絲毫改變。通過實現模式在通過實現理論的過程中已經有一些有趣的探索了。 至此本系列的四篇文章翻譯完結,查看完整系列請移步blogs 由于個人能力知識有限,翻譯過程中難免有紕漏和錯誤,望不吝指正issue ES6 Generators: 完整系列 The Basics...
摘要:本周提交的一份增強建議草案要求將虛擬線程作為標準版的一部分進行預覽。虛擬線程目的是更好地支持編寫和維護高吞吐量并發應用程序。該提案指出,使用虛擬線程不需要學習新的編程模型。我們知道 Go 語言最大亮點之一就是原生支持并發,這得益于 Go 語言的協程機制。一個 go 語句就可以發起一個協程 (goroutin)。 協程本質上是一種用戶態線程,它不需要操作系統來進行調度,而是由用戶程序自行管理...
閱讀 3136·2021-11-11 16:54
閱讀 2290·2021-09-04 16:48
閱讀 3218·2019-08-29 16:08
閱讀 641·2019-08-29 15:13
閱讀 1343·2019-08-29 15:09
閱讀 2659·2019-08-29 12:45
閱讀 1926·2019-08-29 12:12
閱讀 444·2019-08-26 18:27