Reading text file and printing the vowel count

Viewed 36

I am trying to print vowel count from a text file. I am not getting the expected count. I can do this using a regular approach of just counting the character count using strings.Count(). But I want to use concurrency to see how it works. This is the link to text file -> "https://www.gutenberg.org/cache/epub/2600/pg2600.txt"

File size -> 3.36 MB

Below is my code.

Any help is appreciated.

Result I am getting using below code:

A - 145310 E - 188280 I - 116195 O - 131900 U - 47560

Expected result :

A - 202712 E - 313609 I - 172232 O - 190103 U - 64401

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
    "strings"
    "sync"
)

const mb = 1024 * 1024

func main() {

    aCount, eCount, iCount, oCount, uCount := 0, 0, 0, 0, 0

    wg := &sync.WaitGroup{}

    channel := make(chan (string))

    done := make(chan (bool), 1)

    go func() {
        for s := range channel {

            if strings.Contains(strings.ToUpper(s), "A") {
                aCount++
            }
            if strings.Contains(strings.ToUpper(s), "E") {
                eCount++
            }
            if strings.Contains(strings.ToUpper(s), "I") {
                iCount++
            }
            if strings.Contains(strings.ToUpper(s), "O") {
                oCount++
            }
            if strings.Contains(strings.ToUpper(s), "U") {
                uCount++
            }
        }

        done <- true
    }()

    var current int64

    var limit int64 = 0.5 * mb

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func() {
            read(current, limit, "interview.txt", channel)
            fmt.Printf("%d thread has been completed", i)
            wg.Done()
        }()

        current += limit + 1
    }

    // Wait for all go routines to complete.
    wg.Wait()
    close(channel)

    <-done
    close(done)

    fmt.Println("A - ", aCount)
    fmt.Println("E - ", eCount)
    fmt.Println("I - ", iCount)
    fmt.Println("O - ", oCount)
    fmt.Println("U - ", uCount)

}

func read(offset int64, limit int64, fileName string, channel chan (string)) {
    file, err := os.Open(fileName)
    defer file.Close()

    if err != nil {
        panic(err)
    }

    file.Seek(offset, 0)
    reader := bufio.NewReader(file)

    if offset != 0 {
        _, err = reader.ReadBytes(' ')
        if err == io.EOF {
            fmt.Println("EOF")
            return
        }

        if err != nil {
            panic(err)
        }
    }

    var cummulativeSize int64
    for {
        // Break if read size has exceed the chunk size.
        if cummulativeSize > limit {
            break
        }

        b, err := reader.ReadBytes(' ')

        // Break if end of file is encountered.
        if err == io.EOF {
            break
        }

        if err != nil {
            panic(err)
        }

        cummulativeSize += int64(len(b))
        s := strings.TrimSpace(string(b))
        if s != "" {
            channel <- s
        }
    }
}
1 Answers

You have a data race. The results are undefined.

Go: Data Race Detector

$ go run -race vowels.go
==================
WARNING: DATA RACE
Read at 0x00c0000bc068 by goroutine 11:
  main.main.func2()
      vowels.go:55 +0x58

Previous write at 0x00c0000bc068 by main goroutine:
  main.main()
      vowels.go:60 +0x459

Goroutine 11 (running) created at:
  main.main()
      vowels.go:53 +0x434
==================
==================
WARNING: DATA RACE
Read at 0x00c0000bc078 by goroutine 8:
  main.main.func2()
      vowels.go:56 +0x8b

Previous write at 0x00c0000bc078 by main goroutine:
  main.main()
      vowels.go:51 +0x492

Goroutine 8 (running) created at:
  main.main()
      vowels.go:53 +0x434
==================
Related