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.shahbaz...@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+unsubscr...@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+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to