go - memory pooling and buffered channel with multiple goroutines -
i'm creating program create random bson.m documents, , insert them in database. main goroutine generate documents, , push them buffered channel. in same time, 2 goroutines fetch documents channel , insert them in database.
this process take lot of memory , put pressure on garbage colelctor, i'm trying implement memory pool limit number of allocations
here have far:
package main import ( "fmt" "math/rand" "sync" "time" "gopkg.in/mgo.v2/bson" ) type list struct { l []bson.m } func main() { var rndsrc = rand.newsource(time.now().unixnano()) pool := sync.pool{ new: func() interface{} { l := make([]bson.m, 1000) i, _ := range l { m := bson.m{} l[i] = m } return &list{l: l} }, } // buffered channel store generated bson.m docs var record = make(chan list, 3) // start worker insert docs in database := 0; < 2; i++ { go func() { r := range record { fmt.printf("first: %v\n", r.l[0]) // insert ect } }() } // feed channel := 0; < 100; i++ { // object pool instead of creating new 1 list := pool.get().(*list) // re generate documents j, _ := range list.l { list.l[j]["key1"] = rndsrc.int63() } // push docs channel, , return them pool record <- *list pool.put(list) } }
but looks 1 list
used 4 times before being regenerated:
> go run test.go first: map[key1:943279487605002381 key2:4444061964749643436] first: map[key1:943279487605002381 key2:4444061964749643436] first: map[key1:943279487605002381 key2:4444061964749643436] first: map[key1:943279487605002381 key2:4444061964749643436] first: map[key1:8767993090152084935 key2:8807650676784718781] ...
why isn't list regenerated each time ? how can fix ?
the problem have created buffered channel var record = make(chan list, 3)
. hence code:
record <- *list pool.put(list)
may return , entry placed pool before has been consumed. hence underlying slice modified in loop iteration before consumer has had chance consume it. although sending list
value object, remember []bson.m
pointer allocated array , still pointing same memory when send new list
value. hence why seeing duplicate output.
to fix, modify channel send list pointer make(chan *list, 3)
, change consumer put entry in pool once finished, e.g:
for r := range record { fmt.printf("first: %v\n", r.l[0]) // insert etc pool.put(r) // if error occurs }
your producer should sent pointer pool.put
removed, i.e.
record <- list
Comments
Post a Comment