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 [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/golang-nuts/2570eb2e-1b46-4c3a-8792-8064acd7e5db%40googlegroups.com.