Go并发计算MD5

最近实训的后端课作业要求用Go语言写一个扫描文件然后并发计算MD5值,算是对Go语言基本使用的一个小demo,主要是包括了文件扫描,并发和计算MD5这三部分,虽然没学过Go语言,不过Go最大的优势就是简单,如果有其他编程语言的基础的话,语法方面看一看文档上手很快。

文件扫描

首先是文件扫描,这里使用的是递归扫描的方法,因为文件夹之中一般还会嵌套有文件夹,需要递归扫描直到扫描的路径是一个文件而不是一个文件夹, getAllFileName 函数最终返回的是一个包含输入路径下的所有文件绝对路径的数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
func getAllFileName(pathName string) ([]string, error) {
// 定义返回数组
result := []string{}

// 尝试读取输入路径下的文件,如果读取失败则返回空数组
fis, err := ioutil.ReadDir(pathName)
if err != nil {
return result, err
}

// 循环读取文件列表
for _, fi := range fis {
fullname := pathName + "/" + fi.Name()
// 判断文件类型
if fi.IsDir() {
// 如果文件是一个文件夹,则递归读取该文件夹下的文件
temp, err := getAllFileName(fullname)
if err != nil {
fmt.Println(err)
} else {
// 将结果拼接在本次递归的结果后
result = append(result, temp...)
}
} else {
// 如果文件是一个文件,则尝试读取该文件
_, err := os.ReadFile(fullname)
if err != nil {
fmt.Println(err)
} else {
// 成功读取后将文件名添加至结果中
result = append(result, fullname)
}
}
}
// 返回结果
return result, nil
}

计算MD5

得到所有文件的绝对路径后就可以去计算MD5的值了,计算MD5的方式很简单,可以参考这篇文章

1
2
3
4
5
6
7
8
9
10
11
func getMD5(fileName string, isParallel bool) {
// 计算md5,这里仅做计算,不打印也不存储
file, _ := os.ReadFile(fileName)
sum := md5.Sum(file)
hex.EncodeToString(sum[:])

// 这里用于判断是否为并行计算,如果为并行计算需要在计算结束后调用wg.Done()将WaitGroup的计数器减一
if isParallel {
defer wg.Done()
}
}

Go的并发

main函数中我们分别使用并行和串行来计算相同路径下文件的MD5值,并行计算使用WaitGroup来确保并行计算结果全部返回方便计算时间。

官方文档对 WaitGroup 的描述是:一个 WaitGroup 对象可以等待一组协程结束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
func main() {
// 从命令行获取路径, 例子: go run main.go -p "C:\Users\Admin\Desktop"
var pathName string
flag.StringVar(&pathName, "p", "", "pathName")
flag.Parse()

// 获取路径下所以文件的绝对路径
fileName, err := getAllFileName(pathName)
if err != nil {
fmt.Println(err)
return
}
length := len(fileName)

// 并行计算
begin := time.Now()
// 设置worker协程个数
wg.Add(length)
for i := 0; i < length; i++ {
// 新建一个协程去计算
go getMD5(fileName[i], true)
}
// 使用wg.Wait()阻塞,等待所有协程执行结束
wg.Wait()
parallel := time.Since(begin).Seconds()

// 串行计算
begin = time.Now()
for i := 0; i < length; i++ {
getMD5(fileName[i], false)
}
serial := time.Since(begin).Seconds()

// 打印时间
fmt.Println("parallel time: ", parallel)
fmt.Println("serial time: ", serial)
}

测试结果

我们简单的扫描一下一个300M的项目,查看打印结果

1
2
3
go run main.go -p 'project name'
parallel time: 1.1069734
serial time: 3.8719537

可以看出并行计算还是快很多的。


Go并发计算MD5
http://example.com/2022/06/01/Go并发计算MD5/
作者
Sonce
发布于
2022年6月1日
许可协议