本文目錄一覽:
- 1、Golang配置完成後顯示與系統不兼容,怎麼去解決困擾我三個月了求大佬們幫忙看看吧
- 2、Golang 語言深入理解:channel
- 3、一起使用GO(golang) 來做一個後台管理系統系列10 使用mod 來管理包
- 4、Golang 真的好用嗎?
- 5、(十一)golang 內存分析
- 6、Golang配置完成後顯示與系統不兼容,應該如何解決
Golang配置完成後顯示與系統不兼容,怎麼去解決困擾我三個月了求大佬們幫忙看看吧
遇到不兼容問題請給出不兼容的軟件版本信息,像你這個問題需要給出系統版本和go版本。 go 對系統版本是有最低要求的。
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 的實現,使用鎖的隊列實現更簡單,容易實現
一起使用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 真的好用嗎?
好用,優點如下:
並發簡單、效率高
函數可以返回多個參數
垃圾回收(相比c/c++。不過java、c#都有這個優勢)
簡單易上手,語言特性少(也算缺點)
配套工具完善(pprof太好用了)
簡介
Go(又稱Golang)是Google開發的一種靜態強類型、編譯型、並髮型,並具有垃圾回收功能的編程語言。
羅伯特·格瑞史莫(Robert Griesemer),羅勃·派克(Rob Pike)及肯·湯普遜(Ken Thompson)於2007年9月開始設計Go,稍後Ian Lance Taylor、Russ Cox加入項目。Go是基於Inferno操作系統所開發的。Go於2009年11月正式宣布推出,成為開放源代碼項目。
並在Linux及Mac OS X平台上進行了實現,後來追加了Windows系統下的實現。在2016年,Go被軟件評價公司TIOBE 選為「TIOBE 2016 年最佳語言」。 目前,Go每半年發佈一個二級版本(即從a.x升級到a.y)。
(十一)golang 內存分析
編寫過C語言程序的肯定知道通過malloc()方法動態申請內存,其中內存分配器使用的是glibc提供的ptmalloc2。 除了glibc,業界比較出名的內存分配器有Google的tcmalloc和Facebook的jemalloc。二者在避免內存碎片和性能上均比glic有比較大的優勢,在多線程環境中效果更明顯。
Golang中也實現了內存分配器,原理與tcmalloc類似,簡單的說就是維護一塊大的全局內存,每個線程(Golang中為P)維護一塊小的私有內存,私有內存不足再從全局申請。另外,內存分配與GC(垃圾回收)關係密切,所以了解GC前有必要了解內存分配的原理。
為了方便自主管理內存,做法便是先向系統申請一塊內存,然後將內存切割成小塊,通過一定的內存分配算法管理內存。 以64位系統為例,Golang程序啟動時會向系統申請的內存如下圖所示:
預申請的內存劃分為spans、bitmap、arena三部分。其中arena即為所謂的堆區,應用中需要的內存從這裡分配。其中spans和bitmap是為了管理arena區而存在的。
arena的大小為512G,為了方便管理把arena區域劃分成一個個的page,每個page為8KB,一共有512GB/8KB個頁;
spans區域存放span的指針,每個指針對應一個page,所以span區域的大小為(512GB/8KB)乘以指針大小8byte = 512M
bitmap區域大小也是通過arena計算出來,不過主要用於GC。
span是用於管理arena頁的關鍵數據結構,每個span中包含1個或多個連續頁,為了滿足小對象分配,span中的一頁會劃分更小的粒度,而對於大對象比如超過頁大小,則通過多頁實現。
根據對象大小,劃分了一系列class,每個class都代表一個固定大小的對象,以及每個span的大小。如下表所示:
上表中每列含義如下:
class: class ID,每個span結構中都有一個class ID, 表示該span可處理的對象類型
bytes/obj:該class代表對象的位元組數
bytes/span:每個span佔用堆的位元組數,也即頁數乘以頁大小
objects: 每個span可分配的對象個數,也即(bytes/spans)/(bytes/obj)waste
bytes: 每個span產生的內存碎片,也即(bytes/spans)%(bytes/obj)上表可見最大的對象是32K大小,超過32K大小的由特殊的class表示,該class ID為0,每個class只包含一個對象。
span是內存管理的基本單位,每個span用於管理特定的class對象, 跟據對象大小,span將一個或多個頁拆分成多個塊進行管理。src/runtime/mheap.go:mspan定義了其數據結構:
以class 10為例,span和管理的內存如下圖所示:
spanclass為10,參照class表可得出npages=1,nelems=56,elemsize為144。其中startAddr是在span初始化時就指定了某個頁的地址。allocBits指向一個位圖,每位代表一個塊是否被分配,本例中有兩個塊已經被分配,其allocCount也為2。next和prev用於將多個span鏈接起來,這有利於管理多個span,接下來會進行說明。
有了管理內存的基本單位span,還要有個數據結構來管理span,這個數據結構叫mcentral,各線程需要內存時從mcentral管理的span中申請內存,為了避免多線程申請內存時不斷的加鎖,Golang為每個線程分配了span的緩存,這個緩存即是cache。src/runtime/mcache.go:mcache定義了cache的數據結構
alloc為mspan的指針數組,數組大小為class總數的2倍。數組中每個元素代表了一種class類型的span列表,每種class類型都有兩組span列表,第一組列表中所表示的對象中包含了指針,第二組列表中所表示的對象不含有指針,這麼做是為了提高GC掃描性能,對於不包含指針的span列表,沒必要去掃描。根據對象是否包含指針,將對象分為noscan和scan兩類,其中noscan代表沒有指針,而scan則代表有指針,需要GC進行掃描。mcache和span的對應關係如下圖所示:
mchache在初始化時是沒有任何span的,在使用過程中會動態的從central中獲取並緩存下來,跟據使用情況,每種class的span個數也不相同。上圖所示,class 0的span數比class1的要多,說明本線程中分配的小對象要多一些。
cache作為線程的私有資源為單個線程服務,而central則是全局資源,為多個線程服務,當某個線程內存不足時會向central申請,當某個線程釋放內存時又會回收進central。src/runtime/mcentral.go:mcentral定義了central數據結構:
lock: 線程間互斥鎖,防止多線程讀寫衝突
spanclass : 每個mcentral管理着一組有相同class的span列表
nonempty: 指還有內存可用的span列表
empty: 指沒有內存可用的span列表
nmalloc: 指累計分配的對象個數線程從central獲取span步驟如下:
將span歸還步驟如下:
從mcentral數據結構可見,每個mcentral對象只管理特定的class規格的span。事實上每種class都會對應一個mcentral,這個mcentral的集合存放於mheap數據結構中。src/runtime/mheap.go:mheap定義了heap的數據結構:
lock: 互斥鎖
spans: 指向spans區域,用於映射span和page的關係
bitmap:bitmap的起始地址
arena_start: arena區域首地址
arena_used: 當前arena已使用區域的最大地址
central: 每種class對應的兩個mcentral
從數據結構可見,mheap管理着全部的內存,事實上Golang就是通過一個mheap類型的全局變量進行內存管理的。mheap內存管理示意圖如下:
系統預分配的內存分為spans、bitmap、arean三個區域,通過mheap管理起來。接下來看內存分配過程。
針對待分配對象的大小不同有不同的分配邏輯:
(0, 16B) 且不包含指針的對象: Tiny分配
(0, 16B) 包含指針的對象:正常分配
[16B, 32KB] : 正常分配
(32KB, -) : 大對象分配其中Tiny分配和大對象分配都屬於內存管理的優化範疇,這裡暫時僅關注一般的分配方法。
以申請size為n的內存為例,分配步驟如下:
Golang內存分配是個相當複雜的過程,其中還摻雜了GC的處理,這裡僅僅對其關鍵數據結構進行了說明,了解其原理而又不至於深陷實現細節。1、Golang程序啟動時申請一大塊內存並劃分成spans、bitmap、arena區域
2、arena區域按頁劃分成一個個小塊。
3、span管理一個或多個頁。
4、mcentral管理多個span供線程申請使用
5、mcache作為線程私有資源,資源來源於mcentral。
Golang配置完成後顯示與系統不兼容,應該如何解決
可能程序不兼容, 可以更換個版本試試。另外建議參考下程序對配置的要求。
或者右鍵需要運行的程序 選擇兼容性 用兼容模式運行試試。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/190973.html