Go言語でgzip圧縮する場合の圧縮レベルの比較
前回のGolang CafeでGo言語でgzip圧縮する場合に圧縮レベルを指定することができることを学んだのですが、実際にどれほどの差が出るのか気になったので調べてみました。
- NoCompression
- BestSpeed
- BestCompression
- DefaultCompression
の4つのレベルが定義されています。
圧縮対象はGo言語のパッケージのソースコードにしてみました。
対象は1834ファイルで、容量は14.48MB(15,183,311 バイト)あるようです。
検証コードはこちらに置いていますが、前回のGolang Cafeで使用したgzipのサンプルコードを修正して使用しました。
func NoCompression() { compress("output/NoCompression.tar.gz", gzip.NoCompression) } func BestSpeed() { compress("output/BestSpeed.tar.gz", gzip.BestSpeed) } func BestCompression() { compress("output/BestCompression.tar.gz", gzip.BestCompression) } func DefaultCompression() { compress("output/DefaultCompression.tar.gz", gzip.DefaultCompression) } func compress(outfile string, level int) { var file *os.File var err error var writer *gzip.Writer var body []byte if file, err = os.Create(outfile); err != nil { log.Fatalln(err) } defer file.Close() if writer, err = gzip.NewWriterLevel(file, level); err != nil { log.Fatalln(err) } defer writer.Close() tw := tar.NewWriter(writer) defer tw.Close() root := "c:/golang/go/src/pkg" err = filepath.Walk(root, func(path string, fi os.FileInfo, er error) error { if fi.IsDir() { return nil } if body, err = ioutil.ReadFile(path); err != nil { log.Fatalln(err) } rel, err := filepath.Rel(root, path) if err != nil { log.Fatalln(err) } if body != nil { hdr := &tar.Header{ Name: rel, Size: int64(len(body)), } if err := tw.WriteHeader(hdr); err != nil { println(err) } if _, err := tw.Write(body); err != nil { println(err) } } return nil }) }
変更点はファイル名と圧縮レベルを指定できるようにしたのと、filepath.WalkメソッドでGo言語のパッケージのソースファイルの一覧を取得するようにしているだけです。
このコードに対して以下にあるように単純に実行するだけのBenchmarkを書きました。
func BenchmarkNoCompression(b *testing.B) { for i := 0; i < b.N; i++ { NoCompression() } } func BenchmarkBestSpeed(b *testing.B) { for i := 0; i < b.N; i++ { BestSpeed() } } func BenchmarkBestCompression(b *testing.B) { for i := 0; i < b.N; i++ { BestCompression() } } func BenchmarkDefaultCompression(b *testing.B) { for i := 0; i < b.N; i++ { DefaultCompression() } }
結果はこのようになりました。(※見やすいようにフォーマットだけしています)
$ go test -bench . -benchtime 5s testing: warning: no tests to run PASS BenchmarkNoCompression 50 221192650 ns/op BenchmarkBestSpeed 10 738142220 ns/op BenchmarkBestCompression 2 2757157700 ns/op BenchmarkDefaultCompression 5 1392479640 ns/op ok github.com/taknb2nch/golangcafe/12 36.182s
$ ls -l ./output/ total 15260 -rw-r--r-- 1 taknb2nc Administ 4637547 Jan 17 18:48 BestCompression.tar.gz -rw-r--r-- 1 taknb2nc Administ 5354707 Jan 17 18:48 BestSpeed.tar.gz -rw-r--r-- 1 taknb2nc Administ 4666521 Jan 17 18:48 DefaultCompression.tar.gz -rw-r--r-- 1 taknb2nc Administ 16591117 Jan 17 18:48 NoCompression.tar.gz
圧縮レベル | 時間(ns) | 圧縮率(%) |
---|---|---|
NoCompression | 221192650 |
109.2 |
BestSpeed | 738142220 |
35.3 |
BestCompression | 2757157700 |
30.5 |
DefaultCompression | 1392479640 |
30.7 |
圧縮なし(NoCompression)はおいておいて、想像通りの結果となりました。
この結果を見る限りではDefaultCompressionが速度でもファイルサイズでも一番バランスがよさそうですね。BestCompressionはDefaultCompressionに比べて時間は4倍かかっていますが、圧縮率をみるとあまりかわりません。今回の検証対象がテキストファイルだけだったのでこのような結果になったのかもしれません。
単純にコマンドラインで圧縮しても同じような結果になるのでしょうけど、Go言語でも圧縮率を指定して圧縮できるという検証ができたのでとりあえずは納得です。