0

I would like to make the statistics routine conditional so that it only runs on certain cases otherwise it will waste cycles half the time. Right now I have one go routine act as a producer to feed the two consumer routines via buffered channels. Is there a way I can make it so the statistics routine is conditional or is there a better pattern I should follow? Thanks in advance for any and all help!

func main() {
    options()
    go produce(readCSV(loc))
    go process()
    go statistics() // only on flag
    <-done
}

func produce(entries [][]string) {
    regex, err := regexp.Compile(reg)
    if err != nil {
        log.Error(reg + ", is not a valid regular expression")
    } else {
        for _, each := range entries {
            if regex.MatchString(each[col]) {
                matches <- each
                stats <- each // only on flag
            }
        }
    }
    done <- true
}

func process() {
    for {
        match := <-matches
        if len(match) != 0 {
            // PROCESS
        }
    }
}

func statistics() {
    for {
        stat := <-stats
        if len(stat) != 0 {
            // STATISTICS
        }
    }
}
pdago
  • 107
  • 2
  • 9

3 Answers3

1

There is nothing wrong with making this conditional:

var stats chan []string  // Don't initialize stats.

func main() {
    options()
    go produce(readCSV(loc))
    go process()
    if flag {
        stats = make(chan []string, 1024)
        go statistics() // only on flag
    }
    <-done
}

func produce(entries [][]string) {
    regex, err := regexp.Compile(reg)
    if err != nil {
        log.Error(reg + ", is not a valid regular expression")
    } else {
        for _, each := range entries {
            if regex.MatchString(each[col]) {
                matches <- each
                if stats != nil {
                    stats <- each // only on flag
                }
            }
        }
    }
    close(done)
}

func process() {
    for {
        select {
        case match := <-matches:
            if len(match) != 0 {
              // PROCESS
            }
        case <-done:
            return
        }
    }
}

func statistics() {
    for {
        select {
        case stat := <-stats:
            if len(stat) != 0 {
                // STATISTICS
            }
        case <-done:
            return
        }
    }
}
  • That is how I initially tackled it but when the flag is true I get a deadlock error for all go routines being asleep. Any thoughts? – pdago Jul 08 '15 at 03:29
  • You need to make sending to a channel conditional too. This answer shows the correct approach: `if stats != nil { ...` – kostya Jul 08 '15 at 03:31
  • I double checked, its the exact same as the example above – pdago Jul 08 '15 at 03:36
  • I can't give you a definite answer without a complete stacktrace, but my guess is that the deadlock is not because of statistics() but is because of how you handle done. I've updated my answer. Note the select clauses in `statistics` and `process`, and `close(done)` in `produce`. Please check it out and let me know if it fixes your issue. – Soheil Hassas Yeganeh Jul 09 '15 at 15:23
0

Perhaps you're looking for the flag package.

import "flag"

var withStats = flag.Boolean("s", false, "Do statistics")

func main() {
    flag.Parse()
    ...
    if *withStats == true {
        t := statType
        size := 100
        stats := make(chan, t, size)
        go statistics() // only on flag
    }
    ...
}
reedobrien
  • 116
  • 4
0

If you update statistics from many places in your code you might want to add some helper methods. Something like:

type stats struct {
    ch chan []string
}

func (s *stats) update(a []string) {
    if s != nil {
        s.ch <- a
    }
}

func (s *stats) start() {
    if s != nil {
        s.ch = make(chan []string)
        go statistics()
    }
}

var s *stats
if enabled {
    s = new(stats)
}
s.start()

// later in the code
s.update(each)
kostya
  • 9,221
  • 1
  • 29
  • 36
  • Although I don't this is still awesome and will come in handy later down the road. Thank you very much for the share! – pdago Jul 08 '15 at 03:35