You are dealing in double digit nano differences on an IO call - it makes no 
difference. Use whichever code is easier to work with and understand. 

> On May 30, 2020, at 4:45 AM, amarjeetanandsi...@gmail.com wrote:
> 
> 
> Hi
> 
> I have a db package, which needs to return a slice of struct(of user,order 
> etc type).
> In the user pkg, I want the slice of user. To achieve this, I have tried 4 
> ways, As shown below. 
> 
> 
> Attempt 1: Create a callback func using reflection 
> 
> create the user obj & callBack func using reflection & call the callback func 
> with new doc as parameter. This way looks clean to use in user pkg but using 
> reflection is costly. (please see the benchmark @ bottom of this mail)
> package db
> 
> func QueryResults_CallBack_ReflectionFunc(callBackFuncI interface{}) error {
>    defer client.Close()
> 
>    funcType := reflect.TypeOf(callBackFuncI)
>    docType := funcType.In(0).Elem()
>    callBackFunc := reflect.ValueOf(callBackFuncI)
>    arg := make([]reflect.Value, 1)
> 
>    doc := reflect.New(docType)
>    for client.HasMore() {
>       if err := client.ReadDocument(doc.Interface()); err != nil {
>          return err
>       }
>       arg[0] = doc
>       callBackFunc.Call(arg)
>    }
> 
>    return nil
> }
> 
> 
> and at the user pkg side just pass a call back function like...
> package user
> 
> func GetUsers_CallBack_ReflectionFunc() []User {
>    users := make([]User, 0, 5)
>    db.QueryResults_CallBack_ReflectionFunc(func(user *User) {
>       users = append(users, *user)
>    })
>    return users
> }
> 
> 
> 
> 
> Attempt 2: Pass the callback func & user object 
> 
> Pass the callback func & user object  from user to db pkg, so that, the db 
> pkg doesn't have to create one using reflection, thus saving cost of using 
> reflection
> package db
> 
> func QueryResults_CallBack_ObjNFunc(doc interface{}, callBackFunc 
> func(interface{})) error {
>    defer client.Close()
> 
>    for client.HasMore() {
>       if err := client.ReadDocument(doc); err != nil {
>          return err
>       }
>       callBackFunc(doc)
>    }
>    return nil
> }
> 
> 
> 
> and in user package it can be used as -
> package user
> 
> func GetUsers_CallBack_ObjNFunc() []User {
>    users := make([]User, 0, 5)
>    db.QueryResults_CallBack_ObjNFunc(&User{}, func(userI interface{}) {
>       u := userI.(*User)
>       users = append(users, *u)
>    })
>    return users
> }
> 
> 
> Attempt 3: Pass the db client in a callback func
> package db
> 
> func QueryResults_CallBack_DBClient(callBackFunc func(DbClient) error) error {
>    defer client.Close()
> 
>    for client.HasMore() {
>       if err := callBackFunc(client); err != nil {
>          return err
>       }
>    }
>    return nil
> }
> 
> 
> and in user pkg, it can be used as - 
> package user
> 
> func GetUsers_CallBack_DBClient() []User {
>    users := make([]User, 0, 5)
>    db.QueryResults_CallBack_DBClient(func(client db.DbClient) error {
>       user := User{}
>       if err := client.ReadDocument(&user); err != nil {
>          return err
>       }
>       users = append(users, user)
>       return nil
>    })
> 
>    return users
> }
> 
> 
> 
> 
> Attempt 4: Expose the db client
> 
> package db
> 
> func QueryResults_ExposeClient() DbClient {
>    return client
> }
> 
> 
> and in user package, handle the read document logic like...
> package user
> 
> func GetUsers_ExposeClient() []User {
>    users := make([]User, 0, 5)
> 
>    client := db.QueryResults_ExposeClient()
>    for client.HasMore() {
>       user := User{}
>       client.ReadDocument(&user)
>       users = append(users, user)
>    }
>    client.Close() // responsibility of caller to close the client
> 
>    return users
> }
> 
> 
> Benchmark
> ~/go/src/testReflection master* 5s ❯ go test ./user  -cpuprofile cpu.prof 
> -memprofile mem.prof -bench='BenchmarkGetUser*' -run=^a -benchmem
> 
> BenchmarkGetUsers_CallBackReflectionFunc-12         4426987               263 
> ns/op             432 B/op          4 allocs/op
> 
> BenchmarkGetUsers_CallBack_ObjNFunc-12              6293131               186 
> ns/op             384 B/op          2 allocs/op
> 
> BenchmarkGetUsers_CallBackClient-12                 7858377               147 
> ns/op             320 B/op          1 allocs/op
> 
> BenchmarkGetUsers_ExposeClient-12                   10273468              106 
> ns/op             320 B/op          1 allocs/op
> 
> 
> 
> PProf svg 
> https://raw.githubusercontent.com/amarjeetanandsingh/go_reflection_test/master/pprof_cpu.svg
> https://raw.githubusercontent.com/amarjeetanandsingh/go_reflection_test/master/pprof_mem.svg
> 
> 
> Source Code
> You can find the code at 
> https://github.com/amarjeetanandsingh/go_reflection_test
> 
> 
> 
> Based on the performance which approach would you suggest? 
> Or any optimisation you can suggest for CallBack_ReflectionFunc()?
> Or maybe you can purpose a better way? 
>  
> 
> 
> 
> -- 
> You received this message because you are subscribed to the Google Groups 
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to golang-nuts+unsubscr...@googlegroups.com.
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/golang-nuts/2570eb2e-1b46-4c3a-8792-8064acd7e5db%40googlegroups.com.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CA25C97F-05DB-42BD-B9E1-46B4B8A6A9CC%40ix.netcom.com.

Reply via email to