I'm trying to write wc(1) in Go, and I'm experimenting with goroutines in an effort to count large number of input files more efficiently. My code works fine as it is, but I have a hard time implementing a method to summarize the statistics for all the go routines. How can I pass the function variables nl
, nw
, nc
to main and summarize them there once all the go routines have completed their work?
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
ch := make(chan string)
for _, arg := range os.Args[1:] {
go wc(arg, ch)
}
for range os.Args[1:] {
fmt.Println(<-ch)
}
// Todo: summarize results...
}
func wc(arg string, ch chan<- string) {
nl, nw, nc := 0, 0, 0
file, err := os.Open(arg)
if err != nil {
fmt.Println("Can't open file: %v", err)
}
defer file.Close()
scan := bufio.NewScanner(file)
for scan.Scan() {
nl++
line := scan.Text()
words := bufio.NewScanner(strings.NewReader(line))
words.Split(bufio.ScanWords)
for words.Scan() {
nw++
}
runes := bufio.NewReader(strings.NewReader(line))
for {
if _, _, err := runes.ReadRune(); err != nil {
break
} else {
nc++
}
}
}
ch <- fmt.Sprintf("%8d%8d%8d", nl, nw, nc+nl)
}
You're close to the answer! I suggest a quick refacto though to return a Result
object with the numbers, that will allow to easily add them at the end (instead of using strings). So you can use a chan Result
instead of chan string
.
Basically, you can introduce a totalResult
variable, and when iterating on all results, just add the results for nl
, nc
and nw
into that total variable.
package main
import (
"fmt"
"math/rand"
)
// define a struct to hold the result
type Result struct {
nl int
nw int
nc int
}
// this is to be able to use fmt.Println(result)
func (r Result) String() string {
return fmt.Sprintf("%8d%8d%8d", r.nl, r.nw, r.nc+r.nl)
}
func main() {
ch := make(chan Result)
for _, arg := range os.Args[1:] {
go wc(arg, ch)
}
totalResult := Result{}
for range os.Args[1:] {
result := <-ch
fmt.Println(result) // just for debugging
// sum everything
totalResult.nl += result.nl
totalResult.nw += result.nw
totalResult.nc += result.nc
}
fmt.Println("Total result:")
fmt.Println(totalResult)
}
func wc(arg string, ch chan<- Result) {
nl, nw, nc := 0, 0, 0
// your logic to compute nl, nw, nc goes here
ch <- Result{nl: nl, nw: nw, nc: nc + nl}
}
You should get something like this (with 3 files):
37 50 4753
19 106 821
47 255 3806
Total result:
103 411 9380