zstd
Zstandard是一种实时压缩算法,提供高压缩率。它提供了非常广泛的压缩/速度权衡,同时由非常快速的解码器提供支持。实现了高性能压缩算法。现在专注于速度。
该包提供压缩并减压Zstandard内容。
这个包是纯 Go 的,没有使用“不安全”。
该zstd软件包是使用 Go 标准许可证作为开源软件提供的。
目前,该软件包针对 64 位处理器进行了大量优化,在 32 位处理器上会显着降低。
安装
使用go get -u github.com/klauspost/compress
. 该包位于github.com/klauspost/compress/zstd
.
压缩
地位:
稳定 - 可能总是存在细微的错误,已经测试了各种各样的内容,并且该库被多个项目积极使用。该库正在针对所有更新进行模糊测试。
可能仍然存在可能导致边缘情况的数据类型/大小/设置的特定组合,因此一如既往,建议进行测试。
目前,已经实现了高速(最快)和中速(默认)压缩器。
- “Fastest”压缩率大致相当于 zstd 级别 1。
- “Default”压缩率大致相当于 zstd 级别 3(默认)。
- “Better”的压缩率大致相当于 zstd 7 级。
- “Best”压缩率大致相当于 zstd 级别 11。
在速度方面,它通常是 stdlib deflate/gzip 在最快模式下的 2 倍。与 stdlib 相比,压缩率约为 3 级,但通常快 3 倍。
用法
编码器可用于通过io.WriteCloser编码器支持的接口压缩流 或通过EncodeAll函数作为多个独立任务。鼓励较小的编码使用 EncodeAll 函数。使用NewWriter来创建可用于两个新的实例。
要使用默认选项创建编写器,请执行以下操作:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
// Compress input to output.
func Compress(in io.Reader, out io.Writer) error {
enc, err := zstd.NewWriter(out)
if err != nil {
return err
}
_, err = io.Copy(enc, in)
if err != nil {
enc.Close()
return err
}
return enc.Close()
}
|
现在您可以通过将数据写入enc. 输出将在Close()调用时完成写入。即使你的编码失败,你仍然应该调用Close()释放任何可能被阻塞的资源。
以上适用于大编码。但是,只要有可能,请尝试重用编写器。
要重用编码器,您可以使用该Reset(io.Writer)
函数更改为另一个输出。这将允许编码器重用所有资源并避免浪费分配。
当前流编码具有“轻”并发性,这意味着最多 2 个 goroutine 可以处理流的一部分。这与WithEncoderConcurrency(n)
无关,但将来可能会改变。因此,如果您想限制未来更新的并发性,请指定您想要的并发性。
您可以使用WithEncoderLevel()
选项指定所需的压缩级别。目前只能指定预定义的压缩设置。
未来兼容性保证
这将是一个不断发展的项目。使用此包时,重要的是要注意压缩效率和速度都可能会发生变化。
目标是将默认效率保持在默认 zstd(级别 3)。但是,永远不应假定编码保持不变,并且不应使用压缩输出的哈希值进行相似性检查。
可以假设编码器从完全相同的代码版本产生相同的输出。但是,将来可能会打破这种模式,尽管如果没有明确的选项,它们将无法启用。
该编码器并非旨在(并且可能永远不会)输出与参考编码器完全相同的比特流。
另请注意,cgo 解压缩器当前不报告无效输入的所有错误, 省略错误检查,忽略校验 和,并且似乎忽略连接流,即使它是规范的一部分。
块
为了压缩小块,返回的编码器有一个名为EncodeAll(src, dst []byte) []byte
的函数。
EncodeAll
将对 src 中的所有输入进行编码并将其附加到 dst。这个函数可以被并发调用,但每次调用只会在一个 goroutine 上运行。
编码块可以连接在一起,结果将是组合的输入流。使用 EncodeAll 压缩的数据可以使用解码器解码,使用流或DecodeAll.
特别是在编码块时,您应该特别注意重复使用编码器。这将有效地使其在预热期后无需分配即可运行。为了让它在没有分配的情况下完全运行,为所有内容提供一个带有空间的目标缓冲区。
1
2
3
4
5
6
7
8
9
10
11
|
import "github.com/klauspost/compress/zstd"
// Create a writer that caches compressors.
// For this operation type we supply a nil Reader.
var encoder, _ = zstd.NewWriter(nil)
// Compress a buffer.
// If you have a destination buffer, the allocation in the call can also be eliminated.
func Compress(src []byte) []byte {
return encoder.EncodeAll(src, make([]byte, 0, len(src)))
}
|
您可以在创建编写器时使用WithEncoderConcurrency(n)
选项控制并发编码的最大数量。
同时对流和单个块使用编码器是安全的。
表现
我收集了一些速度示例,以将速度和压缩与其他压缩器进行比较。
- file 是输入文件。
- out是使用的压缩机。zskp是这个包吗 zstd是 Datadog cgo 库。gzstd/gzkp是 gzip 标准和这个库。
- level是使用的压缩级别。因为zskp级别 1 是“最快”,级别 2 是“默认”;3 是“更好”,4 是“最好”。
- insize/outsize是输入/输出大小。
- millis 是用于压缩的毫秒数。
- mb/s 是每秒兆字节(2^20 字节)。
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
Silesia Corpus:
<http://sun.aei.polsl.pl/~sdeor/corpus/silesia.zip>
This package:
file out level insize outsize millis mb/s
silesia.tar zskp 1 211947520 73101992 643 313.87
silesia.tar zskp 2 211947520 67504318 969 208.38
silesia.tar zskp 3 211947520 64595893 2007 100.68
silesia.tar zskp 4 211947520 60995370 7691 26.28
cgo zstd:
silesia.tar zstd 1 211947520 73605392 543 371.56
silesia.tar zstd 3 211947520 66793289 864 233.68
silesia.tar zstd 6 211947520 62916450 1913 105.66
silesia.tar zstd 9 211947520 60212393 5063 39.92
gzip, stdlib/this package:
silesia.tar gzstd 1 211947520 80007735 1654 122.21
silesia.tar gzkp 1 211947520 80369488 1168 173.06
GOB stream of binary data. Highly compressible.
<https://files.klauspost.com/compress/gob-stream.7z>
file out level insize outsize millis mb/s
gob-stream zskp 1 1911399616 235022249 3088 590.30
gob-stream zskp 2 1911399616 205669791 3786 481.34
gob-stream zskp 3 1911399616 175034659 9636 189.17
gob-stream zskp 4 1911399616 167273881 29337 62.13
gob-stream zstd 1 1911399616 249810424 2637 691.26
gob-stream zstd 3 1911399616 208192146 3490 522.31
gob-stream zstd 6 1911399616 193632038 6687 272.56
gob-stream zstd 9 1911399616 177620386 16175 112.70
gob-stream gzstd 1 1911399616 357382641 10251 177.82
gob-stream gzkp 1 1911399616 362156523 5695 320.08
The test data for the Large Text Compression Benchmark is the first
10^9 bytes of the English Wikipedia dump on Mar. 3, 2006.
<http://mattmahoney.net/dc/textdata.html>
file out level insize outsize millis mb/s
enwik9 zskp 1 1000000000 343848582 3609 264.18
enwik9 zskp 2 1000000000 317276632 5746 165.97
enwik9 zskp 3 1000000000 292243069 12162 78.41
enwik9 zskp 4 1000000000 275241169 36430 26.18
enwik9 zstd 1 1000000000 358072021 3110 306.65
enwik9 zstd 3 1000000000 313734672 4784 199.35
enwik9 zstd 6 1000000000 295138875 10290 92.68
enwik9 zstd 9 1000000000 278348700 28549 33.40
enwik9 gzstd 1 1000000000 382578136 9604 99.30
enwik9 gzkp 1 1000000000 383825945 6544 145.73
Highly compressible JSON file.
<https://files.klauspost.com/compress/github-june-2days-2019.json.zst>
file out level insize outsize millis mb/s
github-june-2days-2019.json zskp 1 6273951764 699045015 10620 563.40
github-june-2days-2019.json zskp 2 6273951764 617881763 11687 511.96
github-june-2days-2019.json zskp 3 6273951764 524340691 34043 175.75
github-june-2days-2019.json zskp 4 6273951764 503314661 93811 63.78
github-june-2days-2019.json zstd 1 6273951764 766284037 8450 708.00
github-june-2days-2019.json zstd 3 6273951764 661889476 10927 547.57
github-june-2days-2019.json zstd 6 6273951764 642756859 22996 260.18
github-june-2days-2019.json zstd 9 6273951764 601974523 52413 114.16
github-june-2days-2019.json gzstd 1 6273951764 1164400847 29948 199.79
github-june-2days-2019.json gzkp 1 6273951764 1128755542 19236 311.03
VM Image, Linux mint with a few installed applications:
<https://files.klauspost.com/compress/rawstudio-mint14.7z>
file out level insize outsize millis mb/s
rawstudio-mint14.tar zskp 1 8558382592 3667489370 20210 403.84
rawstudio-mint14.tar zskp 2 8558382592 3364592300 31873 256.07
rawstudio-mint14.tar zskp 3 8558382592 3158085214 77675 105.08
rawstudio-mint14.tar zskp 4 8558382592 3020370044 404956 20.16
rawstudio-mint14.tar zstd 1 8558382592 3609250104 17136 476.27
rawstudio-mint14.tar zstd 3 8558382592 3341679997 29262 278.92
rawstudio-mint14.tar zstd 6 8558382592 3235846406 77904 104.77
rawstudio-mint14.tar zstd 9 8558382592 3160778861 140946 57.91
rawstudio-mint14.tar gzstd 1 8558382592 3926257486 57722 141.40
rawstudio-mint14.tar gzkp 1 8558382592 3970463184 41749 195.49
CSV data:
<https://files.klauspost.com/compress/nyc-taxi-data-10M.csv.zst>
file out level insize outsize millis mb/s
nyc-taxi-data-10M.csv zskp 1 3325605752 641339945 8925 355.35
nyc-taxi-data-10M.csv zskp 2 3325605752 591748091 11268 281.44
nyc-taxi-data-10M.csv zskp 3 3325605752 530289687 25239 125.66
nyc-taxi-data-10M.csv zskp 4 3325605752 490907191 65939 48.10
nyc-taxi-data-10M.csv zstd 1 3325605752 687399637 8233 385.18
nyc-taxi-data-10M.csv zstd 3 3325605752 598514411 10065 315.07
nyc-taxi-data-10M.csv zstd 6 3325605752 570522953 20038 158.27
nyc-taxi-data-10M.csv zstd 9 3325605752 517554797 64565 49.12
nyc-taxi-data-10M.csv gzstd 1 3325605752 928656485 23876 132.83
nyc-taxi-data-10M.csv gzkp 1 3325605752 924718719 16388 193.53
|
解压器
状态:稳定 - 可能仍然存在细微的错误,但已经测试了各种各样的内容。
该库正在不断进行模糊测试,由fuzzit.dev 友情提供。模糊测试的主要目的是确保解码器不会崩溃,或在提供任何输入的情况下运行超过其限制。
用法
该包被设计用于两种主要用途,大数据流和较小的内存缓冲区。这些包有两个主要用途。它们都可以通过创建一个Decoder.
对于流媒体使用,一个简单的设置可能如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import "github.com/klauspost/compress/zstd"
func Decompress(in io.Reader, out io.Writer) error {
d, err := zstd.NewReader(in)
if err != nil {
return err
}
defer d.Close()
// Copy content...
_, err = io.Copy(out, d)
return err
}
|
当您不再需要 Reader 来停止运行 goroutine 时,使用“关闭”功能很重要。请参阅下面的“无分配操作”。
对于解码缓冲区,它可能如下所示:
1
2
3
4
5
6
7
8
9
10
11
|
import "github.com/klauspost/compress/zstd"
// Create a reader that caches decompressors.
// For this operation type we supply a nil Reader.
var decoder, _ = zstd.NewReader(nil)
// Decompress a buffer. We don't supply a destination buffer,
// so it will be allocated by the decoder.
func Decompress(src []byte) ([]byte, error) {
return decoder.DecodeAll(src, nil)
}
|
这两种情况都应该提供所需的功能。解码器可用于多个缓冲区的并发解压缩。它只允许运行一定数量的并发操作。要自己调整,请在创建解码器时使用WithDecoderConcurrency(n)
选项。
字典
用字典压缩的数据可以解压。
字典单独添加到解码器。字典由zstd --train
命令生成并包含解码器的初始状态。要添加字典,请使用WithDecoderDicts(dicts ...[]byte)
带有字典数据的选项。可以一次添加多个词典。
字典将自动用于指定它们的数据。重用的解码器仍将包含已注册的词典。
注册多个同一个ID的词典时,会使用最后一个。
压缩数据时可以使用字典。
要启用字典,请使用WithEncoderDict(dict []byte)
. 这里只使用一本字典,即使它没有改进压缩,它也可能会被使用。
必须使用使用的字典来解压缩内容。
对于任何真正的收益,字典都应该使用类似的数据构建。如果使用不合适的字典,输出可能比不使用字典稍大。使用zstd 命令行工具从示例数据构建字典。有关信息,请参阅zstd 字典信息。
目前,使用字典压缩内容存在固定的启动性能损失。随着时间的推移,这可能会得到改善。请注意在实施时测试性能。
无分配操作
解码器设计为在预热后无需分配即可运行。
这意味着您应该存储解码器以获得最佳性能。要重新使用流解码器,请使用Reset(r io.Reader) error
切换到另一个流。即使前一个流失败,解码器也可以安全地重新使用。
要释放资源,您必须在解码器上调用Close()
函数。在此之后它不能再被重用,但所有正在运行的 goroutine 将被停止。因此,如果您不再需要阅读器,则必须使用它。
为了解压缩较小的缓冲区,可以使用单个解码器。解码缓冲区时,您可以提供长度为 0 和预期容量的目标切片。在这种情况下,不应进行不需要的分配。
并发
缓冲区解码器在同一个 goroutine 上执行所有操作,并且不同时执行任何操作。然而,它可以同时解码多个缓冲区。使用WithDecoderConcurrency(n)
来限制。
流解码器操作:
- 一个 goroutine 读取输入并将输入拆分到多个块解码器。
- 许多解码器将解码块。
- goroutine 协调这些块并将历史从一个块发送到下一个。
如此有效,这也意味着解码器将“提前读取”并准备数据以始终可用于输出。
由于“块”非常依赖于先前块流解码的输出,因此只有有限的并发性。
在实践中,这意味着并发通常仅限于有效利用大约 2 个内核。
基准
这些是与datadog cgo 库相比的一些性能示例。
前两个是流式解码,最后一个是较小的输入。
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
|
BenchmarkDecoderSilesia-8 3 385000067 ns/op 550.51 MB/s 5498 B/op 8 allocs/op
BenchmarkDecoderSilesiaCgo-8 6 197666567 ns/op 1072.25 MB/s 270672 B/op 8 allocs/op
BenchmarkDecoderEnwik9-8 1 2027001600 ns/op 493.34 MB/s 10496 B/op 18 allocs/op
BenchmarkDecoderEnwik9Cgo-8 2 979499200 ns/op 1020.93 MB/s 270672 B/op 8 allocs/op
Concurrent performance:
BenchmarkDecoder_DecodeAllParallel/kppkn.gtb.zst-16 28915 42469 ns/op 4340.07 MB/s 114 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/geo.protodata.zst-16 116505 9965 ns/op 11900.16 MB/s 16 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/plrabn12.txt.zst-16 8952 134272 ns/op 3588.70 MB/s 915 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/lcet10.txt.zst-16 11820 102538 ns/op 4161.90 MB/s 594 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/asyoulik.txt.zst-16 34782 34184 ns/op 3661.88 MB/s 60 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/alice29.txt.zst-16 27712 43447 ns/op 3500.58 MB/s 99 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/html_x_4.zst-16 62826 18750 ns/op 21845.10 MB/s 104 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/paper-100k.pdf.zst-16 631545 1794 ns/op 57078.74 MB/s 2 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/fireworks.jpeg.zst-16 1690140 712 ns/op 172938.13 MB/s 1 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/urls.10K.zst-16 10432 113593 ns/op 6180.73 MB/s 1143 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/html.zst-16 113206 10671 ns/op 9596.27 MB/s 15 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallel/comp-data.bin.zst-16 1530615 779 ns/op 5229.49 MB/s 0 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/kppkn.gtb.zst-16 65217 16192 ns/op 11383.34 MB/s 46 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/geo.protodata.zst-16 292671 4039 ns/op 29363.19 MB/s 6 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/plrabn12.txt.zst-16 26314 46021 ns/op 10470.43 MB/s 293 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/lcet10.txt.zst-16 33897 34900 ns/op 12227.96 MB/s 205 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/asyoulik.txt.zst-16 104348 11433 ns/op 10949.01 MB/s 20 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/alice29.txt.zst-16 75949 15510 ns/op 9805.60 MB/s 32 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/html_x_4.zst-16 173910 6756 ns/op 60624.29 MB/s 37 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/paper-100k.pdf.zst-16 923076 1339 ns/op 76474.87 MB/s 1 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/fireworks.jpeg.zst-16 922920 1351 ns/op 91102.57 MB/s 2 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/urls.10K.zst-16 27649 43618 ns/op 16096.19 MB/s 407 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/html.zst-16 279073 4160 ns/op 24614.18 MB/s 6 B/op 0 allocs/op
BenchmarkDecoder_DecodeAllParallelCgo/comp-data.bin.zst-16 749938 1579 ns/op 2581.71 MB/s 0 B/op 0 allocs/op
|
这反映了 2020 年 5 月前后的表现,但这可能已经过时。
ZIP 文件中的 Zstd
可以使用 zstandard 来压缩 zip 档案中的单个文件。虽然这没有得到广泛支持,但它对内部文件很有用。
要支持这些文件的压缩和解压,您必须注册一个压缩器和解压器。
强烈建议在单独的 zip Reader/Writer 上注册(解)压缩器,而不是使用全局注册功能。造成这种情况的主要原因是来自不同包的 2 个注册会导致恐慌。
最好只有一个压缩器和解压缩器,因为它们可以同时用于多个 zip 文件,并且使用单个实例将允许重用某些资源。
请参阅此示例了解如何压缩和解压缩 zip 档案中的文件。
转载
zstd