最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

go?variant底層原理深入解析

 更新時間:2022年11月23日 11:10:11   作者:用戶楊杰  
這篇文章主要為大家介紹了go?variant底層原理深入解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

varint

今天本來在研究 OpenTelemetry 的基準性能測試 github.com/zdyj3170101…,測試不同網絡協(xié)議:grpc, grpc-stream, http, websocket 在發(fā)送不同大小數據包時消耗 cpu,吞吐 的區(qū)別,由 tigrannajaryan 這位大神所寫。

好奇翻了翻該大神的 github 倉庫,發(fā)現了一個同樣神奇的庫。

這個庫也是基準的性能測試,用來測試 go 中不同方法實現的 多類型變量 在消耗 cpu 以及 內存上的區(qū)別。

旨在實現一個能存儲多類型變量并且具有最小 cpu 消耗以及 內存消耗的數據結構。

github.com/tigrannajar…

benchmarks

  • Interface: 接口
  • struct:struct,多個 field 存放不同類型的結構體
  • variant:該庫的時間

struct

struct 是一個結構體,typ 表示當前結構體的類型,不同的 field 分別存儲不同的類型。

type Variant struct {
   typ   variant.Type
   bytes []byte
   str   string
   i     int
   f     float64
}

struct 還有兩種不同的類型。

根據是否返回指針分別為 plainstruct 和 ptrstruct。

而 ptrstruct 相比 plainstruct 就多出一次內存分配,以及增加 cpu 耗時(棧上內存分配幾個移位指令就能完成)。

func StringVariant(v string) Variant {
  return Variant{typ: variant.TypeString, str: v}
} 
?
func StringVariant(v string) *Variant {
  return &Variant{typ: variant.TypeString, str: v}
}

進行 benchmark 后發(fā)現 plainstruct 已經 0 byte 分配了,我也想不出還有其他的優(yōu)化思路。

yangjie05-mac:plainstruct jie.yang05$ go test -bench=. -benchmem plainstruct_test.go  plainstruct.go
Variant size=64 bytes
goos: darwin
goarch: amd64
cpu: VirtualApple @ 2.50GHz
BenchmarkVariantIntGet-10                       1000000000               0.3111 ns/op          0 B/op          0 allocs/op
BenchmarkVariantFloat64Get-10                   1000000000               0.3117 ns/op          0 B/op          0 allocs/op
BenchmarkVariantIntTypeAndGet-10                1000000000               0.3189 ns/op          0 B/op          0 allocs/op
BenchmarkVariantStringTypeAndGet-10             141588165                8.435 ns/op           0 B/op          0 allocs/op
BenchmarkVariantBytesTypeAndGet-10              140932470                8.465 ns/op           0 B/op          0 allocs/op
BenchmarkVariantIntSliceGetAll-10                7293846               165.7 ns/op           640 B/op          1 allocs/op
BenchmarkVariantIntSliceTypeAndGetAll-10         7491408               170.6 ns/op           640 B/op          1 allocs/op
BenchmarkVariantStringSliceTypeAndGetAll-10      7061575               170.1 ns/op           640 B/op          1 allocs/op
?

variant

一個 variant 由指向真實數據的指針 ptr,一個緊湊的 lenandtype 同時表示長度和類型,這個數據結構還根據不同位的系統(tǒng)做了優(yōu)化,以及 capOrVal(在slice類型數據時,就是 cap,非slice類型數據時就是val )。

  • 32位系統(tǒng)下,type 占3位,len 用29位表示
  • 64 位系統(tǒng)下,type占3位,len用63位表示。

Variant 設計主要是為了同時滿足存儲 float64 和 string 的需求。 因為 float64 的存在,必須要有一個 int64 類型的字段存儲 float64 的值。 而 string 的 len 是int類型的字段,就不需要用int64。

type Variant struct {
  // Pointer to the slice start for slice-based types.
  ptr unsafe.Pointer
?
  // Len and Type fields.
  // Type uses `typeFieldBitCount` least significant bits, Len uses the rest.
  // Len is used only for the slice-based types.
  lenAndType int
?
  // Capacity for slice-based types, or the value for other types. For Float64Val type
  // contains the 64 bits of the floating point value.
  capOrVal int64
}

比如創(chuàng)建一個string的時候,ptr 中存放指向數據的指針,而lenAndType 中存儲slice的長度以及 type。 ``

// NewString creates a Variant of TypeString type.
func NewString(v string) Variant {
  hdr := (*reflect.StringHeader)(unsafe.Pointer(&v))
  if hdr.Len > maxSliceLen {
    panic("maximum len exceeded")
  }
?
  return Variant{
    ptr:        unsafe.Pointer(hdr.Data),
    lenAndType: (hdr.Len << typeFieldBitCount) | int(TypeString),
  }
}

為什么 variant 要比 plainstruct 快

分別測試 variant 和 plainstruct 創(chuàng)建 string 的性能:

func createVariantString() Variant { // 防止編譯優(yōu)化掉?
   for i := 0; i < 1; i++ {
      return StringVariant(testutil.StrMagicVal)
   }
   return StringVariant("def")
}
func BenchmarkVariantStringTypeAndGet(b *testing.B) {
   for i := 0; i < b.N; i++ {
      v := createVariantString()
      if v.Type() == variant.TypeString {
         if v.String() == "" {
            panic("empty string")
         }
      } else {
         panic("invalid type")
      }
   }
}

使用 go tool 做性能測試,并查看plainstruct的profile文件:

go test -o=bin -bench=. -v -test.cpuprofile=cpuprofile plainstruct_test.go plainstruct.go
go tool pprof -http=:  bin cpuprofile

同理 variant:

go test -o=bin -bench=. -v -test.cpuprofile=cpuprofile variant_test.go variant.go variant_64.go
 go tool pprof -http=:  bin cpuprofile

variant 的匯編:

plainstruct的匯編:

主要區(qū)別還是plainstrutc的指令數太多,因為struct的字段更多。

variant 可能的優(yōu)化?

variant 其實這里還有一個優(yōu)化的方向,就是在 32 位機器存儲 float64 的時候。 將 float64 拆成兩個 int32,分別用 ptr 和 capOrVal 來存儲。 這樣在 32位系統(tǒng)下,capOrVal 可以由 int64 變成 int,節(jié)省了 4 個字節(jié)。

type Variant struct {
  // Pointer to the slice start for slice-based types.
  ptr unsafe.Pointer
  // Len and Type fields.
  // Type uses `typeFieldBitCount` least significant bits, Len uses the rest.
  // Len is used only for the slice-based types.
  lenAndType int
  capOrVal int
}

以上就是go variant原理深入解析的詳細內容,更多關于go variant的資料請關注腳本之家其它相關文章!

相關文章

  • 詳解Golang如何監(jiān)聽某個函數的開始執(zhí)行和執(zhí)行結束

    詳解Golang如何監(jiān)聽某個函數的開始執(zhí)行和執(zhí)行結束

    這篇文章主要為大家詳細介紹了Golang如何監(jiān)聽某個函數的開始執(zhí)行和執(zhí)行結束,文中的示例代碼講解詳細,有需要的小伙伴可以參考一下
    2024-02-02
  • Golang?Template實現自定義函數的操作指南

    Golang?Template實現自定義函數的操作指南

    這篇文章主要為大家詳細介紹了Golang如何利用Template實現自定義函數的操作,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-02-02
  • 一文搞懂Go語言操作Redis的方法

    一文搞懂Go語言操作Redis的方法

    Redis是一個開源的內存數據庫,在項目開發(fā)中redis的使用也比較頻繁,本文介紹了Go語言中go-redis庫的基本使用。感興趣的小伙伴們可以參考借鑒一下
    2022-09-09
  • golang框架gin的日志處理和zap lumberjack日志使用方式

    golang框架gin的日志處理和zap lumberjack日志使用方式

    這篇文章主要介紹了golang框架gin的日志處理和zap lumberjack日志使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Go語言學習網絡編程與Http教程示例

    Go語言學習網絡編程與Http教程示例

    這篇文章主要為大家介紹了Go語言學習網絡編程與Http教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • Go語言實現聊天小工具的示例代碼

    Go語言實現聊天小工具的示例代碼

    這篇文章主要為大家詳細介紹了如何利用Go語言實現聊天小工具,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • Go中函數的使用細節(jié)與注意事項詳解

    Go中函數的使用細節(jié)與注意事項詳解

    在Go語言中函數可是一等的(first-class)公民,函數類型也是一等的數據類型,下面這篇文章主要給大家介紹了關于Go中函數的使用細節(jié)與注意事項的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-11-11
  • 使用Go語言實現并發(fā)處理CSV文件到數據庫

    使用Go語言實現并發(fā)處理CSV文件到數據庫

    Go?語言的?goroutine?和通道(channel)非常適合用來并發(fā)地處理數據,本文將通過簡單示例介紹一下如何使用Go語言并發(fā)地處理?CSV?文件并將數據插入到數據庫中,感興趣的可以了解下
    2025-01-01
  • golang如何操作csv文件詳解

    golang如何操作csv文件詳解

    這篇文章主要給大家介紹了關于golang如何操作csv文件的相關資料,以及使用Golang導出CSV數據并解決數據亂碼問題的解決辦法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-02-02
  • Go語言中?Print?Printf和Println?的區(qū)別解析

    Go語言中?Print?Printf和Println?的區(qū)別解析

    這篇文章主要介紹了Go語言中?Print?Printf和Println?的區(qū)別,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-03-03

最新評論

江永县| 津市市| 玉林市| 泽普县| 定襄县| 项城市| 辽阳市| 丁青县| 淄博市| 阿坝县| 阿合奇县| 吴忠市| 蕉岭县| 玉环县| 东明县| 旬邑县| 隆尧县| 娱乐| 广德县| 仪征市| 任丘市| 曲松县| 蓝山县| 蓬溪县| 东源县| 洛隆县| 黑龙江省| 噶尔县| 班戈县| 铜川市| 西乌珠穆沁旗| 吐鲁番市| 准格尔旗| 晋中市| 衡山县| 罗源县| 永胜县| 黄山市| 廉江市| 小金县| 饶平县|