My Go Journey
23 June 2021
Vladislav Matúš
Software developer, Nextsum
Vladislav Matúš
Software developer, Nextsum
Task: Program that counts a percentage of a specified letter in all files in a directory
func percentage(input []byte, letter byte) float64 { var letterCount int for _, b := range input { if b == letter { letterCount++ } } return 100.0 * float64(letterCount) / float64(len(input)) }
We will see soon how we can improve this
4Very first version of the main
function's code:
func main() { const requestedLetter = 'a' const dataDir = "../data" files, _ := os.ReadDir(dataDir) for _, file := range files { filePath := path.Join(dataDir, file.Name()) fileContents, err := os.ReadFile(filePath) if err != nil { /* error handling */ } pct := percentage(fileContents, requestedLetter) fmt.Printf("%f%% of %q in file %s\n", pct, requestedLetter, filePath) } }
And now the curiosity kicks in:
requesstedLetter
and dataDir
from the user?YES, we can! (flag package)
requestedLetterIn := flag.String("l", "", "letter that we want to count") dataDir := flag.String("d", "", "the directory") flag.Parse() if len(*requestedLetterIn) != 1 { return } requestedLetter := (*requestedLetterIn)[0]
Usage:
go run . -d ../data -l a
YES, we can! (io.Reader)
f, err := os.Open(filePath) if err != nil { /* error handling */ } pct := percentage(f, requestedLetter) if err = f.Close(); err != nil { /* error handling */ } fmt.Printf("%f%% of %q in file %s\n", pct, requestedLetter, filePath)
func percentage(r io.Reader, letter byte) float64 { var letterCount, allCount int bufR := bufio.NewReader(r) for { b, err := bufR.ReadByte() if err != nil { break } if b == letter { letterCount++ } allCount++ } return 100.0 * float64(letterCount) / float64(allCount) }
YES, we can!
filePathCh := make(chan string) var workerWg sync.WaitGroup // We create a worker pool and thereby limit the maximal number of go routines for i := 0; i < runtime.NumCPU(); i++ { workerWg.Add(1) go func(workerNo int) { defer workerWg.Done() for filePath := range filePathCh { f, err := os.Open(filePath) if err != nil { /* error handling */ } pct := percentage(f, requestedLetter) if err = f.Close(); err != nil { /* error handling */ } fmt.Printf("%f%% of %q in file %s processed by worker %d\n", pct, requestedLetter, filePath, workerNo) } }(i) } for _, file := range files { filePathCh <- path.Join(*dataDir, file.Name()) } close(filePathCh) workerWg.Wait()
Vladislav Matúš
Software developer, Nextsum