Skip to content

Day 87: std.lz4模块:LZ4快速压缩

在数据压缩的世界里,通常需要在压缩率、压缩速度和解压速度之间做出权衡。像Deflate(Zlib, Gzip)这样的算法提供了良好的压缩率,但速度相对较慢。

LZ4是一种极快的压缩算法,其解压速度甚至可以达到内存复制的速度。虽然它的压缩率通常不如Zlib或Zstandard,但对于需要极低延迟的场景,如实时数据流、游戏资源加载和内存中的数据压缩,LZ4是一个绝佳的选择。

Zig标准库通过std.lz4模块,为LZ4提供了原生的、高性能的实现。

LZ4的核心是块压缩(Block Compression)。它独立地压缩和解压缩数据块。

  • lz4.compressBound(input_size): 这是一个重要的辅助函数。它返回在最坏情况下,压缩input_size字节数据所需的最大缓冲区大小。
  • lz4.compress(output, input, options): 将input切片压缩到output切片中。返回实际的压缩大小。
const std = @import("std");
const lz4 = std.lz4;
pub fn main() !void {
const allocator = std.testing.allocator;
const original_data = "This is some data that will be compressed very fast!" ** 5;
// 1. 计算所需的最大缓冲区大小
const bound = lz4.compressBound(original_data.len);
const compressed_buf = try allocator.alloc(u8, bound);
defer allocator.free(compressed_buf);
// 2. 压缩
const compressed_size = try lz4.compress(compressed_buf, original_data, .{});
const compressed_data = compressed_buf[0..compressed_size];
std.debug.print("Original size: {d}, Compressed size: {d}\n", .{
original_data.len,
compressed_data.len,
});
}

lz4.decompress(output, input)用于解压缩。与压缩不同,解压缩时你必须确切地知道原始未压缩数据的大小,并提供一个大小正好合适的output缓冲区。

// ...接上文
// 3. 解压缩
const decompressed_buf = try allocator.alloc(u8, original_data.len);
defer allocator.free(decompressed_buf);
const decompressed_size = try lz4.decompress(decompressed_buf, compressed_data);
std.debug.print("Decompressed size matches original: {}\n", .{decompressed_size == original_data.len});
std.debug.print("Data is identical: {}\n", .{
std.mem.eql(u8, original_data, decompressed_buf)
});

由于其极高的速度,LZ4非常适合在通过网络发送数据之前进行实时压缩,以减少带宽占用,而对延迟的影响最小。

fn send_packet(socket: Stream, data: []const u8) !void {
var compressed_buf: [MAX_PACKET_SIZE]u8 = undefined;
const compressed_size = try lz4.compress(compressed_buf[0..], data, .{});
// 发送压缩后的数据包
try socket.writer().writeAll(compressed_buf[0..compressed_size]);
}

LZ4块格式本身不包含原始大小等元数据,这使得流式处理变得困难。为了解决这个问题,官方定义了LZ4帧格式(Frame Format),它在LZ4数据块的基础上添加了头部和尾部,包含了魔数、帧大小、块大小和校验和等信息。

尝试阅读LZ4帧格式规范,并使用std.lz4的块压缩函数,编写一个简单的lz4.FrameWriter,它可以将写入的数据分块压缩,并添加必要的帧元数据。

  • LZ4帧格式(Frame Format) std.lz4模块本身只提供了核心的块压缩算法。要处理标准的.lz4文件,你需要自己实现对LZ4帧格式的解析和构建。这为你提供了灵活性,但也需要更多的工作。

  • 字典压缩 与Zlib和Zstd一样,LZ4也支持使用预共享字典进行压缩。这对于压缩大量相似的小文件或数据块特别有效。lz4.compress的Options中可以指定字典。

  • 与Zstandard的对比 Zstandard(Zstd)是由LZ4的同一作者Yann Collet在Facebook开发的。Zstd旨在提供类似Zlib的压缩率,但具有接近LZ4的压缩和解压速度。它通常被看作是两全其美的现代选择。对于新项目,如果对压缩率有一定要求,Zstd通常是比LZ4更好的默认选择。

LZ4是压缩算法名人堂中的“速度之王”。当你的首要需求是尽可能快地完成压缩和解压缩,并且可以接受适度的压缩率时,LZ4是无与伦比的选择。

Zig标准库选择原生实现LZ4,再次证明了其对性能的极致追求。通过提供对这种高速算法的直接访问,Zig使开发者能够轻松地在应用程序的性能关键路径上(如数据加载、网络通信和实时系统)实现延迟优化,而无需引入外部依赖。