国产精品免费嫩草研究院|无遮羞动漫在线观看AV|国产麻豆精品传媒AV国产在线|村在线观看|寂寞情人1正版|韩国床震韩国床震古|精品系列专区久久

用golang開發系統軟件的一些細節( 五 )


channelchannel當然也算一種并發容器,其本質上是無鎖隊列 。
需要注意兩點:

  • 為了在多讀多寫條件下維持隊列的數據結構,通常通過CAS+自旋等待來操作關鍵數據 。
因此在大并發下,入隊出隊操作是串行化的,CAS失敗+自旋重試又會帶來cpu使用率升高 。
同樣的,channel沒有那么快 。要避免在劇烈競爭的環境下使用channel 。
  • 通常會使用channel來做生產者-消費者模式的并發結構 。數據數據可以按照一定的規律分區,則可以考慮每個消費者對應一個channel,然后生產者根據數據的key來決定放到哪個channel 。這樣本質上減緩了鎖的競爭 。
其他用sync.Once來懶惰初始化有的運算結果,有一定概率用到,但是又不必每次都計算 。這種情況下,使用sync.Once來懶惰初始化是個好辦法:
var once sync.Oncevar globalXXX *XXXfunc GetXXX() *XXX{  once.Do(func(){    globalXXX = getXXX()  })  return globalXXX}不安全代碼string與[]byte的轉換string與slice的結構本質上是一樣的,可以直接強制轉換:
import ( "reflect" "unsafe")// copy from prometheus source code// NoAllocString convert []byte to stringfunc NoAllocString(bytes []byte) string { return *(*string)(unsafe.Pointer(&bytes))}// NoAllocBytes convert string to []bytefunc NoAllocBytes(s string) []byte { strHeader := (*reflect.StringHeader)(unsafe.Pointer(&s)) sliceHeader := reflect.SliceHeader{Data: strHeader.Data, Len: strHeader.Len, Cap: strHeader.Len} return *(*[]byte)(unsafe.Pointer(&sliceHeader))}上面的代碼可以避免string和[]byte在轉換的時候發生拷貝 。
注意:轉換后的對象一定要立即使用,不要進一步引用到更深的層次中去 。牢記這是不安全代碼,謹慎使用 。強制類型轉換懂C的人,請繞過……
例如一個[]int64的數組要轉換為[]uint64的數組,使用個指針強制轉換就行了 。
package mainimport ( "testing" "unsafe")func TestConvert(t *testing.T) { int64Slice := make([]int64, 0, 100) int64Slice = append(int64Slice, 1, 2, 3) uint64Slice := *(*[]uint64)(unsafe.Pointer(&int64Slice)) t.Logf("%+v", uint64Slice)}還有一種使用場景,要比較兩個大數組是否完全一樣:可以把數組強制轉換為[]byte,然后使用bytes.Compare() 。相當于C中的memcmp()函數 。
類似的操作還很多,推薦這篇文章:《深度解密Go語言之unsafe》
模糊記得一個golang(或是rust)的原則:普通開發者可以使用安全代碼來無顧慮的使用,高手把不安全代碼包裝成安全代碼來提供高性能組件 。數組越界檢查的開銷相比C的數組訪問,為什么golang可以做到很安全?
答案是編譯器加了兩條越界檢查的指令 。每次通過下標訪問數組,就像這樣:
if index<0 || index>=len(slice){  panic("out of index")}return slice[index]這兩條越界檢查指令是有開銷的,請看我的測試:《golang中數組邊界檢查的開銷大約是1.87%~3.12%》
所以,當某些位置使用類似查表法的時候,可以用不安全代碼繞過越界檢查:
slice := make([]byte, 1024*1024)offset = 100b := (*(*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&arr[0])) + uintptr(offset))))編譯/鏈接階段使用盡量新的golang版本理論上,每個新版的golang,都有一定編譯器優化的提升 。

經驗總結擴展閱讀