Created
January 29, 2019 22:01
-
-
Save mordvinov/f5db1c96a3047abc495b1ff137a25234 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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