为了测试 golang `ioutil.ReadAll` 、`io.Copy`、`bufio.NewReader` 性能 我写了三个函数,函数代码如下:
## golang 读取文件性能对比
### `ioutil.ReadAll`
```go
func ReadAll(path string) (fileMD5 string, err error) {
f, err := os.Open(path)
if err != nil {
return fileMD5, err
}
defer f.Close()
body, err := ioutil.ReadAll(f)
if err != nil {
return fileMD5, err
}
hash := sha1.New()
hash.Write(body)
fileMD5 = hex.EncodeToString(hash.Sum(nil))
return fileMD5, nil
}
```
### `io.copy`
```go
func Copy(path string) (fileMD5 string, err error) {
f, err := os.Open(path)
if err != nil {
return fileMD5, err
}
defer f.Close()
md5hash := sha1.New()
if _, err := io.Copy(md5hash, f); err != nil {
return fileMD5, err
}
fileMD5 = hex.EncodeToString(md5hash.Sum(nil))
return fileMD5, nil
}
```
### `bufio.NewReader`
```go
func ReadBuf(path string) (fileMD5 string, err error) {
f, err := os.Open(path)
if err != nil {
return fileMD5, err
}
defer f.Close()
buf := make([]byte, 1024)
reader := bufio.NewReader(f)
md5hash := sha1.New()
for {
n, err := reader.Read(buf)
if err != nil { // 遇到任何错误立即返回,并忽略 EOF 错误信息
if err == io.EOF {
goto stop
}
return fileMD5, err
}
md5hash.Write(buf[:n])
}
stop:
fileMD5 = hex.EncodeToString(md5hash.Sum(nil))
return fileMD5, nil
}
```
### 单元测试
```go
package file_test
import (
"testing"
"filestore/test/file"
)
var (
minPath = "~/6d827d1edddea7c73fb7d6efbb467167839ff2f6.jpg"
maxPath = "/Users/zhanggaoyuan/学习/2004.mkv"
)
func BenchmarkReadAll(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := file.ReadAll(minPath)
if err != nil {
b.Error(err)
return
}
}
}
func BenchmarkCopy(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := file.Copy(minPath)
if err != nil {
b.Error(err)
return
}
}
}
func BenchmarkReadBuf(b *testing.B) {
for i := 0; i < b.N; i++ {
_, err := file.ReadBuf(minPath)
if err != nil {
b.Error(err)
return
}
}
}
```
## 文件大小耗时情况
### 小于等于 `10MB` 的文件耗时情况
准备 6d827d1edddea7c73fb7d6efbb467167839ff2f6.jpg 9.7M 的文件,
执行 `go test -bench=. -benchmem` 就可以看到详细的信息啦
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkReadAll-8 64 17963784 ns/op 33552812 B/op 22 allocs/op
BenchmarkCopy-8 80 12910267 ns/op 33192 B/op 8 allocs/op
BenchmarkReadBuf-8 66 15641888 ns/op 5544 B/op 9 allocs/op
PASS
ok filestore/test/file 3.994s
```
我们可以看出 `BenchmarkCopy` 性能最高,执行 84 次平均时间 12910267 纳秒,也就是 1.2 秒左右的样子啦。
### 小于等于 `40MB` 的文件耗时情况
准备文件 niushop_b2c_mf2.3.zip 37M
执行 `go test -bench=. -benchmem` 就可以看到详细的信息啦
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkReadAll-8 16 63298080 ns/op 134216088 B/op 24 allocs/op
BenchmarkCopy-8 24 48085580 ns/op 33176 B/op 8 allocs/op
BenchmarkReadBuf-8 19 58120592 ns/op 5528 B/op 9 allocs/op
PASS
ok filestore/test/file 4.206s
```
我们还是可以看到 `BenchmarkCopy` 函数性能最高
### 大于等于 `1G` 小于等于 `6G`的文件耗时情况
注意一点的就是当我们测试大文件读取不能直接使用 `ioutil.ReadAll`, 因为这个函数会直接把文件的全部内容加载到内存中,这样会导致内存直接崩溃。我们只使用 `io.copy` 和 bufio.NewReader 函数,太大了刚不住,我也很无奈啊~~????????????????
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkCopy-8 1 8612443012 ns/op 33176 B/op 10 allocs/op
BenchmarkReadBuf-8 1 8924705447 ns/op 5512 B/op 9 allocs/op
PASS
ok filestore/test/file 17.554s
```
我们比较这两个函数的性能发现具体差别不是太大。 单还是 `BenchmarkCopy` 性能更快。。。,好啦没得话说选 `io.copy` 啦
## 接下来分析 `md5` 和 `sha1` 哪个算法计算更快
我们还是用不用的文件做比较,因为有时候很多函数的时间和空间复杂度和大小,数量有关系
### 小于等于`10MB` 的文件耗时情况
`sha1`
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkReadAll-8 64 17963784 ns/op 33552812 B/op 22 allocs/op
BenchmarkCopy-8 80 12910267 ns/op 33192 B/op 8 allocs/op
BenchmarkReadBuf-8 66 15641888 ns/op 5544 B/op 9 allocs/op
PASS
ok filestore/test/file 3.994s
```
`md5`
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkReadAll-8 56 20431688 ns/op 33552750 B/op 22 allocs/op
BenchmarkCopy-8 70 16554352 ns/op 33128 B/op 8 allocs/op
BenchmarkReadBuf-8 57 19220965 ns/op 5480 B/op 9 allocs/op
PASS
ok filestore/test/file 4.202s
```
### 小于等于 `40MB` 的文件耗时情况
`sha1`
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkReadAll-8 16 63298080 ns/op 134216088 B/op 24 allocs/op
BenchmarkCopy-8 24 48085580 ns/op 33176 B/op 8 allocs/op
BenchmarkReadBuf-8 19 58120592 ns/op 5528 B/op 9 allocs/op
PASS
ok filestore/test/file 4.206s
```
`md5`
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkReadAll-8 14 75987790 ns/op 134216024 B/op 24 allocs/op
BenchmarkCopy-8 19 61600369 ns/op 33112 B/op 8 allocs/op
BenchmarkReadBuf-8 15 72338837 ns/op 5464 B/op 9 allocs/op
PASS
ok filestore/test/file 4.339s
```
### 大于等于 `1G` 小于等于 `6G`的文件耗时情况
`sha1`
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkCopy-8 1 8612443012 ns/op 33176 B/op 10 allocs/op
BenchmarkReadBuf-8 1 8924705447 ns/op 5512 B/op 9 allocs/op
PASS
ok filestore/test/file 17.554s
```
`md5`
```
goos: darwin
goarch: amd64
pkg: filestore/test/file
BenchmarkCopy-8 1 8714197367 ns/op 33112 B/op 10 allocs/op
BenchmarkReadBuf-8 1 10077543682 ns/op 5448 B/op 9 allocs/op
PASS
ok filestore/test/file 18.804s
```
> 最终我们可以看到 `sha1` 算法不管是大文件还是小文件都优于 `md5` 文件的性能。至此还用比吗?傻子才不选 `sha1` 算法呢~, 最终选 `io.copy` 和 `sha1q`
原文链接:[https://www.zhanggaoyuan.com/article/58](https://www.zhanggaoyuan.com/article/58)
原文标题:[golang 获取文件摘要算法优化]
本站使用「 [署名-非商业性使用 4.0 国际 (CC BY-NC 4.0)](https://creativecommons.org/licenses/by-nc/4.0/deed.zh)」创作共享协议,转载或使用请署名并注明出处。
有疑问加站长微信联系(非本文作者)