衡阳派盒市场营销有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Go高性能-兩種內存大小為0的數據類型

冬至子 ? 來源:洋芋土豆 ? 作者:真沒什么深度 ? 2023-05-22 17:33 ? 次閱讀

概述

Go 中的空結構體 struct{}{} 的內存大小等于 0,除此之外,還有別的數據類型內存大小也等于 0 嗎?

map 實現 set

Go 的標準庫沒有內置的 Set 類型,在不引用第三方包的情況下,一般是結合內置的 map 類型實現 Set 類型相關功能。

這里假設 Set 元素類型為 int, 那么我們就以 int 作為 map 的鍵類型,以 bool 作為 map 的值類型 (之所以選擇 bool 類型,是因為其大小為 1 個字節,相對其他數據類型可以節省內存,當然,也可以使用 byte 類型,其大小同樣是 1 個字節)。

package main

import "fmt"

// Set 類型定義
type set map[int]bool

// 初始化一個新的 Set
func newSet() set {
    return make(set)
}

// 元素是否存在于與集合中
func (s set) contains(ele int) bool {
    _, ok := s[ele]
    return ok
}

// 添加元素到集合
func (s set) add(ele int) {
    s[ele] = true
}

// 從集合中刪除某個元素
func (s set) remove(ele int) {
    delete(s, ele)
}

func main() {
    s := newSet()

    fmt.Println(s.contains(100))
    s.add(100)
    fmt.Println(s.contains(100))
    s.remove(100)
    fmt.Println(s.contains(100))
}
$ go run main.go

# 輸出如下
false
true
false

上述示例代碼通過內置類型 map 實現了 set 類型相關功能,美中不足的一點在于: 每個元素都要浪費一個 bool 類型作為標識占位符, 能否進一步的優化呢 ?當然是可以的,這就是接下來要講到的 空結構體 了。

空結構體

Go 中的空結構體 struct{}{}一個底層的內置變量,不占用任何內存 :

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    fmt.Printf("size = %d\\n", unsafe.Sizeof(struct{}{}))
}
$ go run main.go

# 輸出如下
size = 0

結合剛才的例子,可以將 struct{}{} 作為 Set 的元素,這樣不論 Set 有多少個元素,標志位 內存占用始終為 0 。

使用 bool 實現 Set

測試代碼

package performance

import (
    "testing"
)

// Set 類型定義, 使用 bool 類型作為占位符
type set map[int]bool

// 初始化一個新的 Set
func newSet() set {
    return make(set)
}

// 元素是否存在于與集合中
func (s set) contains(ele int) bool {
    _, ok := s[ele]
    return ok
}

// 添加元素到集合
func (s set) add(ele int) {
    s[ele] = true
}

// 從集合中刪除某個元素
func (s set) remove(ele int) {
    delete(s, ele)
}

func Benchmark_Compare(b *testing.B) {
    s := newSet()

    for i := 0; i < b.N; i++ {
        s.add(i)
    }
    for i := 0; i < b.N; i++ {
        _ = s.contains(i)
        s.remove(i)
    }
}

運行測試,并將基準測試結果寫入文件:

$ go test -run='^$' -bench=. -count=1 -benchtime=10000000x -benchmem > bool.txt

使用空結構體實現 Set

測試代碼

package performance

import (
    "testing"
)

// Set 類型定義, 使用 bool 類型作為占位符
type set map[int]struct{}

// 初始化一個新的 Set
func newSet() set {
    return make(set)
}

// 元素是否存在于與集合中
func (s set) contains(ele int) bool {
    _, ok := s[ele]
    return ok
}

// 添加元素到集合
func (s set) add(ele int) {
    s[ele] = struct{}{}
}

// 從集合中刪除某個元素
func (s set) remove(ele int) {
    delete(s, ele)
}

func Benchmark_Compare(b *testing.B) {
    s := newSet()

    for i := 0; i < b.N; i++ {
        s.add(i)
    }
    for i := 0; i < b.N; i++ {
        _ = s.contains(i)
        s.remove(i)
    }
}

運行測試,并將基準測試結果寫入文件:

$ go test -run='^$' -bench=. -count=1 -benchtime=10000000x -benchmem > struct.txt

使用 benchstat 比較差異

$ benchstat -alpha=100 bool.txt struct.txt

# 輸出如下
name        old time/op    new time/op    delta
_Compare-8     371ns ± 0%     332ns ± 0%  -10.47%  (p=1.000 n=1+1)

name        old alloc/op   new alloc/op   delta
_Compare-8     44.0B ± 0%     40.0B ± 0%   -9.09%  (p=1.000 n=1+1)

name        old allocs/op  new allocs/op  delta
_Compare-8      0.00           0.00          ~     (all equal)

從輸出的結果中可以看到,相比于使用 bool 作為 Set 元素占位符,使用 空結構體 在性能和內存占用方面,都有了小幅度的優化提升 (10% 左右)。因為時間關系,這里的基準測試只運行了 10000000 次, 運行次數越大,優化的效果越明顯 。感興趣的讀者可以將 -benchtime 調大后看看優化效果。

小結

**Go 中的空結構體 **struct{}{} 不占用任何內存,而且有很清晰的語義性質 (作為占位符使用) 。除了剛才示例中實現 Set 類型功能外, 還可以使用空結構體作為 通道信號標識空對象 等,各種使用場景請讀者自行探索。

彩蛋

除了空結構體 struct{}{} 之外,還有一個鮮為人知的內存大小為 0 的數據類型是: 空數組。但是相對 struct{}{} 豐富的表達性,空數組 使用的場景很少。

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    fmt.Printf("size = %d\\n", unsafe.Sizeof([0]int{}))
}
$ go run main.go

# 輸出如下
size = 0
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • go語言
    +關注

    關注

    1

    文章

    158

    瀏覽量

    9089
收藏 人收藏

    評論

    相關推薦

    LabVIEW的數據類型、存儲格式

    ,左邊的數字代表偏移(offset)數組在內存起始存儲位置的字節數。其他數據類型布爾、字符串、字符串數組、簇、路徑布爾(Boolean)型數據是字節型數據,存儲
    發表于 12-19 15:36

    LabVIEW的數據類型、存儲格式

    ,左邊的數字代表偏移(offset)數組在內存起始存儲位置的字節數。其他數據類型布爾、字符串、字符串數組、簇、路徑布爾(Boolean)型數據是字節型數據,存儲
    發表于 12-19 15:37

    Python中常用的數據類型

    字符串在Python中,加了引號的字符都被認為是字符串,其聲明有三方式,分別是:單引號、雙引號和三引號;Python中的字符串有兩種數據類型,分別是str類型和unicode類型
    發表于 04-19 15:14

    STM32F103xx系列內存大小

    系列內存大小三、閃存概述四、寫和擦除閃存五、讀操作六、總代碼實現一、內存大小內存的容量一般都是 2的整次方倍,系統對內存的識別是以Byte(字節)
    發表于 08-19 08:53

    電腦內存大小怎么查看

    日常辦公或者玩游戲的時候,都需要確認一下電腦內存夠不夠運行將要辦公的軟件或者將要玩游戲的軟件,問題來了,怎么查看電腦內存大小?現在給大家帶來怎么查看電腦內存大小教程。
    發表于 05-27 10:13 ?3620次閱讀

    Linux:測試進程占用的虛擬內存大小

    Linux:測試進程占用的虛擬內存大小
    的頭像 發表于 06-23 09:23 ?2918次閱讀
    Linux:測試進程占用的虛擬<b class='flag-5'>內存大小</b>

    c++ 之布爾類型和引用的學習總結

    在c語言里面我們知道是沒有布爾數據類型的,而在C++中添加了布爾數據類型(bool),它的取值是:true或者false(也就是1或者0),在內存大小上它占用一個字節
    的頭像 發表于 12-24 18:03 ?619次閱讀

    重視變量的數據類型

    不管在什么語言中,定義一個變量時必然要在內存中開辟一個相應大小的空間來存儲該變量。不同的數據類型內存所占的空間大小不同,其所能表示的
    發表于 01-13 15:05 ?1次下載
    重視變量的<b class='flag-5'>數據類型</b>

    C語言中內存四區模型的本質區別和代碼分析

    數據類型可理解創建變量的模具:是固定內存大小的別名。
    的頭像 發表于 03-09 14:45 ?1091次閱讀

    什么是數據類型轉換

    常用的3種數據類型:1、Python數據類型第一:字符串(str)。 2、Python數據類型第二:整數(int)。 3、Pytho
    的頭像 發表于 02-23 15:21 ?1821次閱讀

    CODESYS變量類型的范圍和所占內存大小

    在使用通訊和數據類型轉換時,需要特別注意數據類型的范圍和所占存儲空間的大小,為了方便查詢,在這里和大家歸納總結下。
    的頭像 發表于 05-25 14:57 ?6340次閱讀
    CODESYS變量<b class='flag-5'>類型</b>的范圍和所占<b class='flag-5'>內存大小</b>

    Verilog最常用的2種數據類型

    Verilog 最常用的 2 種數據類型就是線網(wire)與寄存器(reg),其余類型可以理解兩種數據類型的擴展或輔助。
    的頭像 發表于 05-29 16:27 ?2448次閱讀
    Verilog最常用的2<b class='flag-5'>種數據類型</b>

    redis的五種數據類型

    Redis是一高性能內存數據庫,常用于緩存、任務隊列、分布式鎖等場景。它提供了多種數據類型來滿足各種不同的需求,包括字符串(string
    的頭像 發表于 11-16 11:06 ?695次閱讀

    weblogic設置jvm內存大小

    WebLogic是一Java EE應用服務器,用于構建和部署企業級Java應用程序。在配置WebLogic服務器時,設置JVM的內存大小非常重要,這可以提高應用程序的性能和可靠性。本文將詳細介紹
    的頭像 發表于 12-05 14:44 ?3146次閱讀

    eclipse設置jvm內存大小

    內存大小,并對其背后的原理進行解釋。 JVM(Java虛擬機)是Java程序的運行環境,它負責將Java字節碼翻譯成機器碼,以便在不同的平臺上執行。JVM使用內存來存儲運行時對象和執行過程中的臨時數據。如果JVM的
    的頭像 發表于 12-06 11:43 ?1954次閱讀
    网络百家乐官网| 神人百家乐官网赌场| 临潭县| 真人百家乐官网策略| 澳门百家乐有赢钱的吗| 丰禾国际娱乐| 百家乐官网如何赚洗码| 大发888官方删除| 网上百家乐官网娱乐平台| 职业百家乐的玩法技巧和规则| 99棋牌游戏| e世博百家乐娱乐场| 太阳城亚洲| 顶尖百家乐学习| 威海市| 百家乐赌博破解| 百家乐官网最好打法与投注| 大发888迅雷下载免费| 巴西百家乐官网的玩法技巧和规则| 大发888真钱娱乐 博彩| 百家乐7scs娱乐网| 百家乐官网出千的方法| 百家乐官网视频游戏平台| 乐享百家乐的玩法技巧和规则 | 富田太阳城二手房| 广东百家乐主论坛| 百家乐官网免佣台| 大发888官方df888gwyxpt| 风水罗盘里的24山| 阳原县| 大发888游戏平台 df888ylcxz46| 玩百家乐如何硬| 香港百家乐官网六合彩| 优博国际| 皇冠足球| 仪陇县| 百家乐透明发牌机| 百家乐现金投注信誉平台| 新时代百家乐官网娱乐城| 阿拉善盟| 百家乐官网注码调整|