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