本文目錄一覽:
- 1、Golang 語言深入理解:channel
- 2、有沒有用golang寫的開源ERP系統
- 3、一起使用GO(golang) 來做一個後台管理系統系列10 使用mod 來管理包
- 4、Golang什麼時候會觸發GC
Golang 語言深入理解:channel
本文是對 Gopher 2017 中一個非常好的 Talk�: [Understanding Channel](GopherCon 2017: Kavya Joshi – Understanding Channels) 的學習筆記,希望能夠通過對 channel 的關鍵特性的理解,進一步掌握其用法細節以及 Golang 語言設計哲學的管窺蠡測。
channel 是可以讓一個 goroutine 發送特定值到另一個 gouroutine 的通信機制。
原生的 channel 是沒有緩存的(unbuffered channel),可以用於 goroutine 之間實現同步。
關閉後不能再寫入,可以讀取直到 channel 中再沒有數據,並返回元素類型的零值。
gopl/ch3/netcat3
首先從 channel 是怎麼被創建的開始:
在 heap 上分配一個 hchan 類型的對象,並將其初始化,然後返回一個指向這個 hchan 對象的指針。
理解了 channel 的數據結構實現,現在轉到 channel 的兩個最基本方法: sends 和 receivces ,看一下以上的特性是如何體現在 sends 和 receives 中的:
假設發送方先啟動,執行 ch – task0 :
如此為 channel 帶來了 goroutine-safe 的特性。
在這樣的模型里, sender goroutine – channel – receiver goroutine 之間, hchan 是唯一的共享內存,而這個唯一的共享內存又通過 mutex 來確保 goroutine-safe ,所有在隊列中的內容都只是副本。
這便是著名的 golang 並發原則的體現:
發送方 goroutine 會阻塞,暫停,並在收到 receive 後才恢復。
goroutine 是一種 用戶態線程 , 由 Go runtime 創建並管理,而不是操作系統,比起操作系統線程來說,goroutine更加輕量。
Go runtime scheduler 負責將 goroutine 調度到操作系統線程上。
runtime scheduler 怎麼將 goroutine 調度到操作系統線程上?
當阻塞發生時,一次 goroutine 上下文切換的全過程:
然而,被阻塞的 goroutine 怎麼恢復過來?
阻塞發生時,調用 runtime sheduler 執行 gopark 之前,G1 會創建一個 sudog ,並將它存放在 hchan 的 sendq 中。 sudog 中便記錄了即將被阻塞的 goroutine G1 ,以及它要發送的數據元素 task4 等等。
接收方 將通過這個 sudog 來恢復 G1
接收方 G2 接收數據, 並發出一個 receivce ,將 G1 置為 runnable :
同樣的, 接收方 G2 會被阻塞,G2 會創建 sudoq ,存放在 recvq ,基本過程和發送方阻塞一樣。
不同的是,發送方 G1如何恢復接收方 G2,這是一個非常神奇的實現。
理論上可以將 task 入隊,然後恢復 G2, 但恢復 G2後,G2會做什麼呢?
G2會將隊列中的 task 複製出來,放到自己的 memory 中,基於這個思路,G1在這個時候,直接將 task 寫到 G2的 stack memory 中!
這是違反常規的操作,理論上 goroutine 之間的 stack 是相互獨立的,只有在運行時可以執行這樣的操作。
這麼做純粹是出於性能優化的考慮,原來的步驟是:
優化後,相當於減少了 G2 獲取鎖並且執行 memcopy 的性能消耗。
channel 設計背後的思想可以理解為 simplicity 和 performance 之間權衡抉擇,具體如下:
queue with a lock prefered to lock-free implementation:
比起完全 lock-free 的實現,使用鎖的隊列實現更簡單,容易實現
有沒有用golang寫的開源ERP系統
沒有用golang寫的開源ERP系統,這個我計劃業餘時間開發一個,作為學習golang的練習。
另外,metasfresh和axelor是基於java, erpnext是基於python, viennaadvantage是基於net的通過後台配置自動生成較為美觀的前端界面的企業應用快速開發平台,具有很高的開發速度。
從erp的角度,後起之秀metasfresn是功能最齊全的,適合中大型企業的開源erp(在庫存採購銷售製造各模塊加入了大量支持大型企業的功能),缺點是設計高度複雜,代碼難度極大。
而從開發框架的角度,viennaadvantage結合.net/c#,則是上手最容易的,支持saas的企業應用快速開發平台。
一起使用GO(golang) 來做一個後台管理系統系列10 使用mod 來管理包
原項目採用gopath來管理的引用庫,但有小夥伴反應說包不好下,雖然我把對應的包做了百度雲盤共享,但小夥伴們仍然感覺不太好用。特別是最近把go SDK升級到1.18.在管理包上終於下決心使用mod來重新重構下包管理。
一、配置啟用Mod
首先那:
確定是否開啟了
如果沒有開啟請開啟它。開啟命令執行:
#設置 使用七牛雲下載
來看下現在的配置:
二、創建項目
上邊都說了如何開啟了。下面介紹下如何使用
1. 可以隨便找一個目錄創建項目:myGoProjectNew
這個時候查看目錄下會多出一個go.mod的文件:
裡面也有了。標識了下SDK的版本1.18
2. 創建 main.go文件
3. 執行:
這時候就會自動下載引用了。
查看Go.mod文件
最後放兩張效果圖:
感覺還可以得點贊收藏哦。想要源碼的私信我獲取源碼。
Golang什麼時候會觸發GC
Golang採用了三色標記法來進行垃圾回收,那麼在什麼場景下會觸發這個回收動作呢?
源碼主要位於文件 src/runtime/mgc.go go version 1.16
觸發條件從大方面說,可分為 手動觸發 和 系統觸發 兩種方式。手動觸發一般很少用,主要由開發者通過調用 runtime.GC() 函數來實現,而對於系統自動觸發是 運行時 根據一些條件判斷來進行的,這也正是本文要介紹的內容。
不管哪種觸發方式,底層回收機制是一樣的,所以我們先看一下手動觸發,根據它來找系統觸發的條件。
可以看到開始執行GC的是 gcStart() 函數,它有一個 gcTrigger 參數,是一個觸發條件結構體,它的結構體也很簡單。
其實在Golang 內部所有的GC都是通過 gcStart() 函數,然後指定一個 gcTrigger 的參數來開始的,而手動觸髮指定的條件值為 gcTriggerCycle 。 gcStart 是一個很複雜的函數,有興趣的可以看一下源碼實現。
對於 kind 的值有三種,分別為 gcTriggerHeap 、 gcTriggerTime 和 gcTriggerCycle 。
運行時會通過 gcTrigger.test() 函數來決定是否需要觸發GC,只要滿足上面基中一個即可。
到此我們基本明白了這三種觸發GC的條件,那麼對於系統自動觸發這種,Golang 從一個程序的開始到運行,它又是如何一步一步監控到這個條件的呢?
其實 runtime 在程序啟動時,會在一個初始化函數 init() 里啟用一個 forcegchelper() 函數,這個函數位於 proc.go 文件。
為了減少系統資源佔用,在 forcegchelper 函數里會通過 goparkunlock() 函數主動讓自己陷入休眠,以後由 sysmon() 監控線程根據條件來恢復這個gc goroutine。
可以看到 sysmon() 會在一個 for 語句里一直判斷這個 gcTriggerTime 這個條件是否滿足,如果滿足的話,會將 forcegc.g 這個 goroutine 添加到全局隊列里進行調度(這裡 forcegc 是一個全局變數)。
調度器在調度循環 runtime.schedule 中還可以通過垃圾收集控制器的 runtime.gcControllerState.findRunnabledGCWorker 獲取並執行用於後台標記的任務。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/199986.html