Thanks for comments. The status00 should be not-buffered (status00 = make(chan *Data)); was rate limiting on two channels.
On Sunday, August 28, 2016 at 8:16:50 PM UTC+4:30, Henrik Johansson wrote: > > The race is between the len call and the use of the channel. Entries can > have been added in between. > > On Sun, Aug 28, 2016, 17:40 dc0d <kaveh.sh...@gmail.com <javascript:>> > wrote: > >> Would you please elaborate on that? >> >> As I understand it there is no concurrent use of len happening here. It's >> a for loop and all calling to len is happening sequentially. Unless the >> channels make the code inside cases of one select statement concurrent - >> which will be super confusing for me. >> >> >> On Sunday, August 28, 2016 at 8:03:10 PM UTC+4:30, Jan Mercl wrote: >> >>> Using len(ch) like this in a concurrency scenario is a big no because >>> then the value you get carries 0 bits of useful information. It's not a >>> data race, it's worse, the race is semantic and not fixable without >>> removing the use of len(ch). >>> >>> On Sun, Aug 28, 2016, 17:26 dc0d <kaveh.sh...@gmail.com> wrote: >>> >> TL;DR >>>> >>>> Does assigning a (buffered) channel, already in a variable, to a second >>>> variable, affects the result of len function? >>>> >>>> Long version: >>>> What is happening here? - Code at the end; Go 1.7. >>>> >>>> *Output 1*: >>>> >>>> Nine times: >>>> [ info ] 2016/08/28 19:51:28 LEN_BEFORE=0 >>>> >>>> [ info ] 2016/08/28 19:51:28 LEN=7 >>>> >>>> [ info ] 2016/08/28 19:51:28 S00=7 >>>> >>>> But if the second case gets commented like this: >>>> >>>> case <-limiter.C: >>>> // if len(actualBuffer) > 0 { >>>> // buffer = actualBuffer >>>> // } else { >>>> // buffer = nil >>>> // } >>>> >>>> It works as expected; *Output2*: >>>> >>>> [ info ] 2016/08/28 19:54:28 LEN_BEFORE=0 >>>> >>>> [ info ] 2016/08/28 19:54:28 LEN=7 >>>> >>>> [ info ] 2016/08/28 19:54:28 S00=7 >>>> >>>> [ info ] 2016/08/28 19:54:29 LEN_BEFORE=7 >>>> >>>> [ info ] 2016/08/28 19:54:30 LEN_BEFORE=7 >>>> >>>> [ info ] 2016/08/28 19:54:31 LEN_BEFORE=7 >>>> >>>> [ info ] 2016/08/28 19:54:32 LEN_BEFORE=7 >>>> >>>> [ info ] 2016/08/28 19:54:33 LEN_BEFORE=7 >>>> >>>> [ info ] 2016/08/28 19:54:34 LEN_BEFORE=7 >>>> >>>> [ info ] 2016/08/28 19:54:35 LEN_BEFORE=7 >>>> >>>> [ info ] 2016/08/28 19:54:36 LEN_BEFORE=7 >>>> ... >>>> >>>> Code: >>>> >>>> package main >>>> >>>> >>>> import ( >>>> "log" >>>> "time" >>>> >>>> >>>> "github.com/comail/colog" >>>> ) >>>> >>>> >>>> func status00Channeler() { >>>> <-start >>>> >>>> >>>> limiter := time.NewTicker(time.Second / maxMsgPerSec) >>>> fetchLimiter := time.NewTicker(time.Second) >>>> >>>> >>>> var buffer chan *Data >>>> actualBuffer := make(chan *Data, maxMsgPerSec) >>>> db, err := newDB() >>>> if err != nil { >>>> log.Panic(err) >>>> } >>>> >>>> >>>> FIRST: >>>> for { >>>> select { >>>> case <-interrupted: >>>> break FIRST >>>> case <-limiter.C: >>>> // if len(actualBuffer) > 0 { >>>> // buffer = actualBuffer >>>> // } else { >>>> // buffer = nil >>>> // } >>>> case i := <-buffer: >>>> select { >>>> case status00 <- i: // will block here >>>> case <-interrupted: >>>> break FIRST >>>> } >>>> case <-fetchLimiter.C: >>>> log.Printf("LEN_BEFORE=%d", len(actualBuffer)) >>>> if len(actualBuffer) > 0 { >>>> continue >>>> } >>>> >>>> >>>> s00, err := db.GetIncomings() >>>> if err != nil { >>>> log.Println(`error:`, err) >>>> time.Sleep(time.Second) >>>> continue >>>> } >>>> if s00 == nil || len(s00) == 0 { >>>> continue >>>> } >>>> >>>> >>>> FILL_BUFFER: >>>> for _, v := range s00 { >>>> select { >>>> case actualBuffer <- v: >>>> default: >>>> break FILL_BUFFER >>>> } >>>> } >>>> >>>> >>>> log.Printf("LEN=%d", len(actualBuffer)) >>>> log.Printf("S00=%d", len(s00)) >>>> } >>>> } >>>> } >>>> >>>> >>>> func main() { >>>> go status00Channeler() >>>> close(start) >>>> >>>> >>>> <-time.After(time.Second * 30) >>>> } >>>> >>>> >>>> var ( >>>> status00 = make(chan *Data, maxMsgPerSec) >>>> ) >>>> >>>> >>>> type Data struct{} >>>> >>>> >>>> const ( >>>> maxMsgPerSec = 60 >>>> ) >>>> >>>> >>>> func newDB() (*DB, error) { >>>> res := new(DB) >>>> return res, nil >>>> } >>>> >>>> >>>> func (db *DB) GetIncomings() ([]*Data, error) { >>>> var res []*Data >>>> res = append(res, &Data{}) >>>> res = append(res, &Data{}) >>>> res = append(res, &Data{}) >>>> res = append(res, &Data{}) >>>> res = append(res, &Data{}) >>>> res = append(res, &Data{}) >>>> res = append(res, &Data{}) >>>> >>>> >>>> return res, nil >>>> } >>>> >>>> >>>> type DB struct{} >>>> >>>> >>>> func init() { >>>> colog.Register() >>>> } >>>> >>>> >>>> var ( >>>> start = make(chan struct{}) >>>> interrupted = make(chan struct{}) // comes from sys interrupts >>>> SIGINT, SIGTERM, etc >>>> ) >>>> >>>> >>>> -- >>>> 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...@googlegroups.com. >>> >>> >>>> For more options, visit https://groups.google.com/d/optout. >>>> >>> -- >>> >>> -j >>> >> -- >> 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...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > -- 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. For more options, visit https://groups.google.com/d/optout.