Golang 实现多协程读取并计算文件数字的平方和

Golang 的协程非常好用

上次面试时,面试官要求手写代码,题目:
1. 多个文件中存在着一串用空格隔开的数字
2. 读取文件中的数字,计算多个文件的平方和
3. 使用多协程方式

代码:

package main

import (
    "flag"
    "fmt"
    "io/ioutil"
    "os"
    "strconv"
    "strings"
    "time"
)

func power(num string) int {
    n, err := strconv.Atoi(num)
    if err != nil {
        fmt.Printf("something is wrong, the string:%s\n", num)
        return 0
    }
    return n * n
}

//文件中的数字已空格隔开
func readFileAndCalc(file string) []int {
    result := make([]int, 0)
    bytes, _ := ioutil.ReadFile(file)
    //若不去除,可能会出现末尾字符问题
    str := strings.Replace(string(bytes), "\n", "", -1)
    nums := strings.Split(str, " ")
    for _, num := range nums {
        result = append(result, power(num))
    }
    fmt.Printf("File:%s result:%v\n", file, result)
    return result
}

func comparelCalc(pathDir string) error {
    f, err := os.Stat(pathDir)
    if err != nil {
        return err
    } else if !f.IsDir() {
        return fmt.Errorf("path:%v is not the Dirent", pathDir)
    }

    result := 0
    files, _ := ioutil.ReadDir(pathDir)
    ch := make(chan []int, len(files)) //带缓存区的int[] Channel
    for _, f := range files {
        //非目录
        if !f.IsDir() {
            file := fmt.Sprintf("%s/%s", pathDir, f.Name()) //file完整路径
            go func(f string) {
                res := readFileAndCalc(f)
                ch <- res //结果通知
            }(file)
        }
    }

    ov := make(chan struct{}, 0)
    go func() {
        i := 0
        for nums := range ch {
            for _, num := range nums {
                result = result + num
            }
            i++
            if i == len(files) {
                ov <- struct{}{}
            }
        }
    }()

    //超过两分钟,没有结果 ---> 结束
    select {
    case <-time.After(120 * time.Second):
        close(ch)
        return fmt.Errorf("time out")
    case <-ov:
        fmt.Printf("all file result = %d\n", result)
        close(ch)
    }
    return nil
}

//test
func main() {
    path := flag.String("path", "/home/test/test", "Input your path")
    if err := comparelCalc(*path); err != nil {
        fmt.Println(err)
    }
}

结果验证:

# ls /home/test/test
ddd  dmm  mm
# go run comparelCalc.go -path=/home/test/test
File:/home/test/test/ddd result:[1 9 16]
File:/home/test/test/mm result:[1 9 25 25 9 25 9 64 121 484 1936 484 14884 8100]
File:/home/test/test/dmm result:[1 9 25 25 484]
all file result = 26746

你可能感兴趣的:(golang,面试)