用Golang对文件Hash
曾几何时,题主曾用golang写过一个hash的工具,这次打算测试一下对文件的几种不同读取方式的比较。
- 使用
io/ioutl.ReadAll
- 使用
io.Copy
- 使用
bufio.Reader
+io.Copy
当前目录下有个20M左右的文件poe.tgz
,新建了main_test.go
文件,这次使用SHA1
测试。
~ ls -l ./poe.tgz
-rw------- 1 ... ... 20726272 12 7 18:22 ./poe.tgz
~ shasum -a 1 ./poe.tgz
0bd099caa5ac2be51075085daea9cbac89d8a6be ./poe.tgz
上代码:
package main
import (
"bufio"
"crypto/sha1"
"fmt"
"io"
"io/ioutil"
"os"
"runtime"
"testing"
)
const (
fname = "./poe.tgz"
hashSum = "0bd099caa5ac2be51075085daea9cbac89d8a6be"
)
func copyFile() {
f, err := os.Open(fname)
if err != nil {
panic(err)
return
}
defer f.Close()
h := sha1.New()
_, err = io.Copy(h, f)
if err != nil {
panic(err)
return
}
if fmt.Sprintf("%x", h.Sum(nil)) != hashSum {
panic(fmt.Errorf("not equal"))
}
}
func readAll() {
runtime.GC()
f, err := os.Open(fname)
if err != nil {
panic(err)
return
}
defer f.Close()
h := sha1.New()
bs, err := ioutil.ReadAll(f)
if err != nil {
panic(err)
return
}
_, err = h.Write(bs)
if err != nil {
panic(err)
return
}
if fmt.Sprintf("%x", h.Sum(nil)) != hashSum {
panic(fmt.Errorf("not equal"))
}
}
func bufioRead() {
f, err := os.Open(fname)
if err != nil {
panic(err)
return
}
defer f.Close()
br := bufio.NewReader(f)
h := sha1.New()
_, err = io.Copy(h, br)
if err != nil {
panic(err)
return
}
if fmt.Sprintf("%x", h.Sum(nil)) != hashSum {
panic(fmt.Errorf("not equal"))
}
}
func BenchmarkCopy(b *testing.B) {
for i := 0; i < b.N; i++ {
copyFile()
}
}
func BenchmarkBufio(b *testing.B) {
for i := 0; i < b.N; i++ {
bufioRead()
}
}
func BenchmarkReadall(b *testing.B) {
for i := 0; i < b.N; i++ {
readAll()
}
}
~ go test -bench=".*" -benchmem main_test.go
testing: warning: no tests to run
BenchmarkCopy-4 30 34397326 ns/op 33087 B/op 8 allocs/op
BenchmarkBufio-4 50 37697430 ns/op 4492 B/op 9 allocs/op
BenchmarkReadall-4 30 47578226 ns/op 67108143 B/op 30 allocs/op
PASS
ok command-line-arguments 5.480s
结果发现,无论是效率还是内存,bufio.Reader
+io.Copy
都是最优的方式,其次是io.Copy
,而io/ioutl.ReadAll
读取了全部文件到内存。
后又换了个0.5K
的小文件进行测试,发现差距就比较明显了
~ go test -bench=".*" -benchmem main_test.go
testing: warning: no tests to run
BenchmarkCopy-4 100000 14969 ns/op 33057 B/op 8 allocs/op
BenchmarkBufio-4 200000 8618 ns/op 4473 B/op 9 allocs/op
BenchmarkReadall-4 10000 240270 ns/op 3360 B/op 16 allocs/op
PASS
ok command-line-arguments 5.882s
而且还可以看出,无论数据量大小,io.Copy
和bufio.Reader
始终都使用了32K
和4K
的缓冲区,当然看源码里面更清楚。
—END—