亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

我可以優化這個 Go 反射函數,讓它不那么慢嗎?

我可以優化這個 Go 反射函數,讓它不那么慢嗎?

Go
慕婉清6462132 2023-03-07 10:56:34
我正在開展一個項目,我需要為所有將受支持的方法構建部分更新。每個部分更新都需要一個不同的結構,具有不同的字段和字段數量,并且不知道哪些將存在或不存在。我決定遍歷每個結構字段,如果存在,則將其添加到數組中以在最后返回。我還花了一些時間對幾個似乎最現實的函數進行基準測試來解決這個問題,并幫助做出決定。所有的結構字段都是指針??紤]到這一點,這些就是我編寫的函數。注意:我無法為此創建一個 playground 示例,因為它不支持基準測試。我將鏈接完整的課程,并將解釋放在上面。為每個部分更新結構創建一個映射函數,我將在其中分別檢查每個字段。如果該字段不是nil,我會將值放入以 [key,value] 格式存儲的二維數組中。處理完結構后,返回數組。創建一個使用泛型和反射來執行與上述相同的映射函數。
查看完整描述

1 回答

?
慕慕森

TA貢獻1856條經驗 獲得超17個贊

// main.go

package main


import (

    "reflect"

    "strings"

    "time"

)


type updateRequest struct {

    FieldOne   *string    `json:"field_one,omitempty"`

    FieldTwo   *string    `json:"field_two,omitempty"`

    FieldThree *string    `json:"field_three,omitempty"`

    FieldFour  *string    `json:"field_four,omitempty"`

    FieldFive  *string    `json:"field_five,omitempty"`

    FieldSix   *time.Time `json:"field_six,omitempty" time_format:"2006-01-02"`

}


// Mapping function that would need to be recreated for each partial update struct.

func ManualUpdateRequestMapping(req *updateRequest) [][]string {

    vals := make([][]string, 0, 6)

    if req.FieldOne != nil {

        vals = append(vals, []string{"field_one", *req.FieldOne})

    }


    if req.FieldTwo != nil && req.FieldThree != nil {

        vals = append(vals, []string{"field_two", *req.FieldTwo}, []string{"field_three", *req.FieldThree})

    }


    if req.FieldFour != nil {

        vals = append(vals, []string{"field_four", *req.FieldFour})

    }


    if req.FieldFive != nil {

        vals = append(vals, []string{"field_five", *req.FieldFive})

    }


    if req.FieldSix != nil {

        vals = append(vals, []string{"field_six", req.FieldSix.Format(time.RFC3339)})

    }


    return vals

}


// Generics and Reflection function

func ReflectUpdateRequestMapping[T *updateRequest](str T) [][]string {

    valHolder := reflect.ValueOf(*str)

    if valHolder.Kind() != reflect.Struct {

        return nil

    }

    vals := make([][]string, 0, valHolder.NumField())

    for i := 0; i < valHolder.NumField(); i++ {

        if valHolder.Field(i).IsNil() {

            continue

        }

        spl := strings.Split(valHolder.Type().Field(i).Tag.Get("json"), ",")


        if valHolder.Field(i).Elem().Type() != reflect.TypeOf(time.Time{}) {

            vals = append(vals, []string{spl[0], valHolder.Field(i).Elem().String()})

        } else {

            vals = append(vals, []string{spl[0], valHolder.Field(i).Interface().(*time.Time).Format(time.RFC3339)})

        }

    }

    return vals

}

這是我運行的基準方法:

// main_test.go

package main


import (

    "testing"

    "time"

)


func BenchmarkBoth(b *testing.B) {


    field1 := "testfield1"

    field2 := "testfield2"

    field3 := "testfield3"

    field4 := "testfield4"

    field5 := "testfield5"

    date1, _ := time.Parse(time.RFC3339, "2004-10-16T12:40:53.00Z")


    str := &updateRequest{

        FieldOne:   &field1,

        FieldTwo:   &field2,

        FieldThree: &field3,

        FieldFour:  &field4,

        FieldFive:  &field5,

        FieldSix:   &date1,

    }

    b.Run("ManualUpdateRequestMapping", func(b *testing.B) {

        for i := 0; i < b.N; i++ {

            _ = ManualUpdateRequestMapping(str)

        }

    })


    b.Run("ReflectUpdateRequestMapping", func(b *testing.B) {

        for i := 0; i < b.N; i++ {

            _ = ReflectUpdateRequestMapping(str)

        }

    })

}

以下是使用的 CPU 和測試結果:


cpu: 12th Gen Intel(R) Core(TM) i9-12900KF

BenchmarkBoth/ManualUpdateRequestMapping-24              3560083           331.9 ns/op       368 B/op          8 allocs/op

BenchmarkBoth/ReflectUpdateRequestMapping-24             1393377           866.7 ns/op       648 B/op         21 allocs/op

PASS

ok      com.example.stack   3.745s

我預計反射功能會更慢,但不會慢 ~2.5 倍。它還似乎在每次迭代中分配了大約 2.5 倍的資源。是我在上面的代碼中搞砸了什么,還是反射慢了那么多?


如果有任何建議可以使上面的代碼更高效,我愿意接受所有建議。我已經使用 Go 工作了大約 3 個月,所以如果我在上面的代碼中犯了任何 Golang 叛國罪,請寬容我。:)


查看完整回答
反對 回復 2023-03-07
  • 1 回答
  • 0 關注
  • 93 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號