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

GO 反射對性能的影響分析

 更新時間:2023年01月06日 14:31:39   作者:nil  
這篇文章主要為大家介紹了GO 反射對性能的影響分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

寫在前面

今天在公司寫了一段代碼,判斷一個變量是否為空值,由于判斷的類型太少,code review的時候同事說還有很多類型沒有考慮到,并且提到有沒有開源的包做這個事,于是找了一段assert.IsEmpty里面的代碼。但是這段代碼用到了反射。在code review的時候同事又提到了反射影響性能。

基于此,這里對比了一下兩種方式實習(xí)IsEmpty的性能問題。廢話不多說,上代碼。

代碼

最開始的代碼

func IsEmpty(val interface{}) bool {
	if val == nil {
		return true
	}
	switch v := val.(type) {
	case int:
		return v == int(0)
	case int8:
		return v == int8(0)
	case int16:
		return v == int16(0)
	case int32:
		return v == int32(0)
	case int64:
		return v == int64(0)
	case string:
		return v == ""
	default:
		return false
	}
}

由于目前場景里面只需要判斷這幾種數(shù)據(jù)類型,因此只實現(xiàn)了幾種。這種做法明細(xì)很不好,將來如果有別人用怎么辦?這是一種偷懶的做法,不是一個高級程序員應(yīng)該有的素質(zhì)。

在同事提出可能會有其他數(shù)據(jù)類型的時候,想著類型太多,窮舉容易漏,于是在網(wǎng)上找了一下開源的包,遺憾沒有找到。但是想到了assert.Empty函數(shù),于是看了一下源代碼,找到了它的實現(xiàn)方法。

// isEmpty gets whether the specified object is considered empty or not.
func isEmpty(object interface{}) bool {
	// get nil case out of the way
	if object == nil {
		return true
	}
	objValue := reflect.ValueOf(object)
	switch objValue.Kind() {
	// collection types are empty when they have no element
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
		return objValue.Len() == 0
		// pointers are empty if nil or if the value they point to is empty
	case reflect.Ptr:
		if objValue.IsNil() {
			return true
		}
		deref := objValue.Elem().Interface()
		return isEmpty(deref)
		// for all other types, compare against the zero value
	default:
		zero := reflect.Zero(objValue.Type())
		return reflect.DeepEqual(object, zero.Interface())
	}
}

于是把這段代碼復(fù)制過來,code review的時候同事說反射會影響性能(其實我覺得還好,不知道大家覺得它對性能影響有多大,歡迎留言討論),于是我又改了一版。結(jié)合了上面兩種方法。先判斷是不是基礎(chǔ)數(shù)據(jù)類型,如果不是再用反射。

const (
	IntZero     = int(0)
	Int8Zero    = int8(0)
	Int16Zero   = int16(0)
	Int32Zero   = int32(0)
	Int64Zero   = int64(0)
	UintZero    = uint(0)
	Uint8Zero   = uint8(0)
	Uint16Zero  = uint16(0)
	Uint32Zero  = uint32(0)
	Uint64Zero  = uint64(0)
	Float32Zero = float32(0)
	Float64Zero = float64(0)
	StringZero  = ""
)
func IsEmpty(data interface{}) bool {
	if data == nil {
		return false
	}
	switch v := data.(type) {
	case bool:
		return false
	case *bool:
		return v == nil
	case int:
		return v == IntZero
	case *int:
		return v == nil || *v == IntZero
	case int8:
		return v == Int8Zero
	case *int8:
		return v == nil || *v == Int8Zero
	case int16:
		return v == Int16Zero
	case *int16:
		return v == nil || *v == Int16Zero
	case int32:
		return v == Int32Zero
	case *int32:
		return v == nil || *v == Int32Zero
	case int64:
		return v == Int64Zero
	case *int64:
		return v == nil || *v == Int64Zero
	case uint:
		return v == UintZero
	case *uint:
		return v == nil || *v == UintZero
	case uint8:
		return v == Uint8Zero
	case *uint8:
		return v == nil || *v == Uint8Zero
	case uint16:
		return v == Uint16Zero
	case *uint16:
		return v == nil || *v == Uint16Zero
	case uint32:
		return v == Uint32Zero
	case *uint32:
		return v == nil || *v == Uint32Zero
	case uint64:
		return v == Uint64Zero
	case *uint64:
		return v == nil || *v == Uint64Zero
	case float32:
		return v == Float32Zero
	case *float32:
		return v == nil || *v == Float32Zero
	case float64:
		return v == Float64Zero
	case *float64:
		return v == nil || *v == Float64Zero
	case string:
		return v == StringZero
	case *string:
		return v == nil || *v == StringZero
	default:
		kind := reflect.TypeOf(data).Kind()
		if kind == reflect.Ptr {
			dataKind := reflect.ValueOf(data).Elem().Kind()
			if dataKind == reflect.Invalid || dataKind == reflect.Struct {
				return reflect.ValueOf(data).IsNil()
			} else {
				return false
			}
		} else if kind == reflect.Slice || kind == reflect.Map {
			// slice
			return reflect.ValueOf(data).Len() == 0
		} else if kind == reflect.Struct {
			// struct
			return false
		} else {
			panic("not support type. you can support by yourself")
		}
	}
}

得到第三版。

性能分析

代碼提交之后我一直在想第一版和第二版性能到底差別有多大。其實這個時候我偷懶了,沒有做性能分析,做個Bench分析一下很簡單,這件事一直在我心里,過了一天終于寫了一段代碼比對一下性能。

func BenchmarkTestIsEmpty(t *testing.B) {
	v1 := false
	v2 := true
	var v3 *bool
	v4 := int(0)
	var v5 *int
	v6 := int64(0)
	var v7 *int64
	v8 := ""
	var v9 *string
	v10 := "test"
	v11 := float64(0.00)
	v12 := float64(0.01)
	testCases := []TestCase{
		{input: v1, want: false},
		{input: &v1, want: false},
		{input: v2, want: false},
		{input: &v2, want: false},
		{input: v3, want: true},
		{input: v4, want: true},
		{input: &v4, want: true},
		{input: v5, want: true},
		{input: int(1), want: false},
		{input: v6, want: true},
		{input: &v6, want: true},
		{input: v7, want: true},
		{input: int64(1), want: false},
		{input: v8, want: true},
		{input: &v8, want: true},
		{input: v9, want: true},
		{input: v10, want: false},
		{input: &v10, want: false},
		{input: v11, want: true},
		{input: &v11, want: true},
		{input: v12, want: false},
		{input: &v12, want: false},
	}
	for i, testCase := range testCases {
		result := IsEmpty(testCases[i].input)
		assert.Equal(t, testCase.want, result)
	}
}
func BenchmarkTestIsEmptyV1(t *testing.B) {
	v1 := false
	v2 := true
	var v3 *bool
	v4 := int(0)
	var v5 *int
	v6 := int64(0)
	var v7 *int64
	v8 := ""
	var v9 *string
	v10 := "test"
	v11 := float64(0.00)
	v12 := float64(0.01)
	testCases := []TestCase{
		{input: v1, want: true},
		{input: &v1, want: true},
		{input: v2, want: false},
		{input: &v2, want: false},
		{input: v3, want: true},
		{input: v4, want: true},
		{input: &v4, want: true},
		{input: v5, want: true},
		{input: int(1), want: false},
		{input: v6, want: true},
		{input: &v6, want: true},
		{input: v7, want: true},
		{input: int64(1), want: false},
		{input: v8, want: true},
		{input: &v8, want: true},
		{input: v9, want: true},
		{input: v10, want: false},
		{input: &v10, want: false},
		{input: v11, want: true},
		{input: &v11, want: true},
		{input: v12, want: false},
		{input: &v12, want: false},
	}
	for i, testCase := range testCases {
		result := IsEmptyV1(testCases[i].input)
		assert.Equal(t, testCase.want, result)
	}
}

運(yùn)行

go test -bench=.  -benchmem

結(jié)果

goos: darwin
goarch: amd64
pkg: common/util
cpu: Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
BenchmarkTestIsEmpty-12           120820              9635 ns/op               0 B/op          0 allocs/op
BenchmarkTestIsEmptyV1-12         103664             11582 ns/op              72 B/op          8 allocs/op
PASS
ok      common/util     5.149s

  • ns:每次運(yùn)行耗費(fèi)的世界。時間復(fù)雜的相差10倍
  • B:每次運(yùn)行分配的字節(jié)數(shù)??梢姺欠瓷浒娌恍枰~外的內(nèi)存
  • allocs:每次運(yùn)行分配內(nèi)存次數(shù)。

綜上可見,性能差別挺大的。如果只看運(yùn)行時間,相差了10倍。確實反射影響性能,以后還是少用為好,最好不要在循環(huán)里面用。

最終解決辦法

最終結(jié)合第一版和第二版,寫出了第三版。

寫在后面

要善于利用工具,不會的就去學(xué)習(xí),不能偷懶。

今天看到「字節(jié)跳動技術(shù)團(tuán)隊」一個直播,幾位掘金小冊大佬在分享自己是如何寫文章、如何學(xué)習(xí)的,感受挺深。

寫文章要:

  • 1.列提綱
  • 2.利用碎片化的時間積累、記錄
  • 3.利用周末大片的時間思考文章
  • 4.文章寫完自己對知識的認(rèn)知又提升了一個層次,利人利己

寫文章不要:

  • 1.太在意工具。有的人寫文章之前在想用什么打草稿、列提綱、寫思維導(dǎo)圖,在你想這個的時候內(nèi)心其實已經(jīng)在打退堂鼓了。你應(yīng)該直接打開一個文本編輯器或者控制臺等任何能寫文字的地方,甚至微信都行
  • 2.不要在意有多少人會閱讀你的文章。寫完了你自己也會有新的認(rèn)識
  • 3.定時清理收藏夾。不要只放到收藏夾里,里面的東西要定時整理、清理

以上就是GO 反射對性能的影響分析的詳細(xì)內(nèi)容,更多關(guān)于GO 反射性能分析的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • go解析YAML文件(多文檔解析)

    go解析YAML文件(多文檔解析)

    本文介紹了如何使用GO語言和client-go庫處理YAML文件,特別是在Kubernetes環(huán)境下,分析了YAML的特點,如簡潔性、易讀性、可嵌套性等,并展示了相關(guān)代碼實現(xiàn),包括單文檔和多文檔的處理方法,感興趣的可以了解一下
    2024-10-10
  • 一文帶你熟悉Go語言中的分支結(jié)構(gòu)

    一文帶你熟悉Go語言中的分支結(jié)構(gòu)

    這篇文章主要和大家分享一下Go語言中的分支結(jié)構(gòu)(if?-?else-if?-?else、switch),文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Go語言有一定的幫助,需要的可以參考一下
    2022-11-11
  • Go語言使用singleflight解決緩存擊穿

    Go語言使用singleflight解決緩存擊穿

    在構(gòu)建高性能的服務(wù)時,緩存是優(yōu)化數(shù)據(jù)庫壓力和提高響應(yīng)速度的關(guān)鍵技術(shù),但使用緩存也會帶來一些問題,其中就包括緩存擊穿,下面我們就來看看Go語言中如何使用singleflight解決緩存擊穿問題吧
    2024-03-03
  • 詳解以go思想去處理js異常拋棄trycatch

    詳解以go思想去處理js異常拋棄trycatch

    這篇文章主要為大家介紹了詳解以go思想去處理js異常拋棄trycatch,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 從源碼解析golang Timer定時器體系

    從源碼解析golang Timer定時器體系

    本文詳細(xì)介紹了Go語言中的Timer和Ticker的使用方式、錯誤使用方式以及底層源碼實現(xiàn),Timer是一次性的定時器,而Ticker是循環(huán)定時器,正確使用時需要注意返回的channel和垃圾回收問題,Go 1.23版本對定時器進(jìn)行了改進(jìn),優(yōu)化了垃圾回收和停止、重置相關(guān)方法
    2025-01-01
  • Golang中的信號(Signal)機(jī)制詳解

    Golang中的信號(Signal)機(jī)制詳解

    Signal 是一種操作系統(tǒng)級別的事件通知機(jī)制,進(jìn)程可以響應(yīng)特定的系統(tǒng)信號,這些信號用于指示進(jìn)程執(zhí)行特定的操作,如程序終止、掛起、恢復(fù)等,Golang 的標(biāo)準(zhǔn)庫 os/signal 提供了對信號處理的支持,本文將詳細(xì)講解 Golang 是如何處理和響應(yīng)系統(tǒng)信號的,需要的朋友可以參考下
    2024-01-01
  • Go中過濾范型集合性能示例詳解

    Go中過濾范型集合性能示例詳解

    這篇文章主要為大家介紹了Go中過濾范型集合性能示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 深入探究Golang中flag標(biāo)準(zhǔn)庫的使用

    深入探究Golang中flag標(biāo)準(zhǔn)庫的使用

    在本文中,我們將深入探討 flag 標(biāo)準(zhǔn)庫的實現(xiàn)原理和使用技巧,以幫助讀者更好地理解和掌握該庫的使用方法,文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2023-04-04
  • Go 容器遍歷的實現(xiàn)示例

    Go 容器遍歷的實現(xiàn)示例

    Go 語言提供的基礎(chǔ)容器,免不了要查詢?nèi)萜髦械臄?shù)據(jù),那么是如何實現(xiàn)遍歷的呢?本文將會介紹幾種常用容易的遍歷及其使用。感興趣的可以了解一下
    2021-06-06
  • Golang Mutex實現(xiàn)互斥的具體方法

    Golang Mutex實現(xiàn)互斥的具體方法

    Mutex是Golang常見的并發(fā)原語,在開發(fā)過程中經(jīng)常使用到,本文主要介紹了Golang Mutex實現(xiàn)互斥的具體方法,具有一定的參考價值,感興趣的可以了解一下
    2023-04-04

最新評論

临沂市| 岑溪市| 陇西县| 富源县| 阆中市| 邢台县| 上饶县| 蓝田县| 砚山县| 吉水县| 旅游| 始兴县| 彰武县| 西平县| 镇原县| 淮南市| 武邑县| 荆州市| 固始县| 清远市| 岳普湖县| 项城市| 鸡泽县| 南漳县| 桃园市| 平原县| 高陵县| 玉山县| 商都县| 寿光市| 富蕴县| 古丈县| 增城市| 澎湖县| 永胜县| 枝江市| 井冈山市| 湘潭县| 波密县| 武乡县| 许昌县|