Skip to content

Instantly share code, notes, and snippets.

@mordvinov
Created January 29, 2019 22:01
Show Gist options
  • Select an option

  • Save mordvinov/f5db1c96a3047abc495b1ff137a25234 to your computer and use it in GitHub Desktop.

Select an option

Save mordvinov/f5db1c96a3047abc495b1ff137a25234 to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"log"
"os"
"strconv"
"strings"
"sync"
)
var (
totalCounter int
lineCh = make(chan string)
sumCh = make(chan int)
done = make(chan int, 1)
)
func main() {
if len(os.Args) != 4 {
log.Fatal("use: go run main.go [workers] [path_to_file] [substring]")
}
var wg sync.WaitGroup
workers, err := strconv.Atoi(os.Args[1])
if err != nil || workers < 1 {
log.Fatalf("[ERROR] workers must be int and greater than 0")
}
for i := 1; i < workers+1; i++ {
wg.Add(1)
go processLine(&wg, i, os.Args[3])
}
go counter()
f, err := os.Open(os.Args[2])
if err != nil {
log.Fatalf("[ERROR] can't open file: %s", err)
}
defer closeFile(f)
err = readFile(f)
if err != nil {
log.Fatalf("[ERROR] can't process file: %s", err)
}
wg.Wait()
close(sumCh)
<-done
log.Printf("[INFO] main: total_count=%d", totalCounter)
}
// processLine process input line and counts word
func processLine(wg *sync.WaitGroup, i int, substr string) {
n := 0
log.Printf("[INFO] process#%d: start\n", i)
for {
select {
case line, ok := <-lineCh:
if !ok {
log.Printf("[INFO] process#%d: stop(handled jobs: %d)\n", i, n)
wg.Done()
return
}
n++
sumCh <- strings.Count(strings.ToLower(line), substr)
}
}
}
// counter sums word
func counter() {
log.Println("[INFO] counter: start")
for {
select {
case num, ok := <-sumCh:
if !ok {
log.Println("[INFO] counter: stop")
done <- 0
return
}
totalCounter += num
}
}
}
// readFile read file by line and runs goroutines for processing
func readFile(file *os.File) error {
sc := bufio.NewScanner(file)
n := 0
for sc.Scan() {
n++
lineCh <- sc.Text()
}
close(lineCh)
log.Printf("[INFO] readFile: len(lines)=%d", n)
return sc.Err()
}
// closeFile close file descriptor and handles error if that occurred
func closeFile(file *os.File) {
err := file.Close()
if err != nil {
log.Printf("[WARN] can't close file: %s", err)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment