[ 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
case <-limiter.C:
// if len(actualBuffer) > 0 {
// buffer = actualBuffer
// } else {
// buffer = nil
// }
[ 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
...
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
)
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).
--
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
As Jan notes, Len(ch) is usually not what you want becuase any value returned from that expression is considered stale in the presence of multiple goroutines.
The race is between the len call and the use of the channel. Entries can have been added in between.
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).