我能否改进 Rust zip crate 的性能问题?

11

这是我的基准测试程序:

extern crate zip;

use std::fs::File;
use std::io::copy;
use zip::write::FileOptions;
use zip::ZipWriter;

fn main() {
    let mut src = File::open("/tmp/src.mxf").unwrap(); // 624 Mb file.
    let dest = File::create("/tmp/test.zip").unwrap();
    let mut zip_writer = ZipWriter::new(dest);

    zip_writer
        .start_file("src.mxf", FileOptions::default())
        .unwrap();
    copy(&mut src, &mut zip_writer).unwrap();

    zip_writer.finish().unwrap();
}

使用发布模式编译程序:

time ./zip_bench
./zip_bench  62,68s user 146,21s system 99% cpu 3:28,91 total

使用系统zip二进制文件压缩得到的相同文件:

time zip /tmp/test2.zip /tmp/src.mxf
zip /tmp/test2.zip /tmp/src.mxf  13,77s user 0,19s system 99% cpu 13,965 total

系统和Rust压缩之间的时间差大约为14倍(对于相似的输出文件,大小差异微不足道)。

我的代码中是否有什么错误可以解释Rust性能问题?我该如何改进它以接近系统性能?


4
我会尝试设置压缩级别。即使最终文件大小相似,如果文件不太容易压缩,则并不意味着压缩级别相似。此外,在这里明确提到了性能不够优化 当前实现在速度方面仍然比像zlib和miniz这样的C库差一些。。因此,也许可以使用一些ffi来使用zlib进行压缩以改善性能。 - PeterT
尝试使用“CompressionMethod::Stored”(无压缩):没有性能提升!还尝试重新实现“copy”(增加缓冲区大小,默认为8k):同样没有性能提升。 - Benoit Courtine
1
好奇。但似乎你不是唯一遇到这个问题的人:https://github.com/mvdnes/zip-rs/issues/88 - PeterT
9
你尝试过使用BufReader/BufWriter来包装你的File吗? - Jmb
@Jmb 谢谢,这帮了我很多。使用BufWriter后,压缩速度比本地zip命令慢3倍,这是一个巨大的改进。 - Benoit Courtine
1
@BenoitCourtine 你是否也添加了 BufReader?在两端进行缓冲对于获得高性能的 I/O 是很重要的。 - Zenton
1个回答

3

我没有您的测试数据,所以我在一个大小为3.7GB的Debian DVD ISO上操作。我还假设您所谓的“系统zip”与Arch zip包大致相同。

从您的原始代码开始,更新zip crate(如移动到flate2而不是deflate)有所帮助:

time ./zipbench 

real    2m29.285s
user    2m23.396s
sys     0m4.066s

time zip test2.zip  debian-10.4.0-amd64-DVD-1.iso 
  adding: debian-10.4.0-amd64-DVD-1.iso (deflated 1%)

real    1m42.709s
user    1m38.066s
sys     0m3.386s

Zip工具只快了两倍左右,而且我们甚至还没有改变我们的代码,只是将一些crate和Rust本身更新了大约一年。

我们可以使用BufReaderBufWriter给我们的Rust添加缓冲IO:

fn main() -> io::Result<()> {
    let mut src = BufReader::new(File::open("./debian-10.4.0-amd64-DVD-1.iso")?);
    dest = BufWriter::new(File::create("./test.zip")?);
    let mut zip_writer = ZipWriter::new(dest);

    zip_writer.start_file("src.mxf", FileOptions::default())?;
    // This is only workable because we're only writing one file to our ZIP.
    let mut zip_writer = BufWriter::new(zip_writer);
    io::copy(&mut src, &mut zip_writer)?;

    Ok(())
}

这带给我们一个小小的性能提升,但并不是非常显著:

time ./zipbench

real    2m25.348s
user    2m20.105s
sys     0m3.894s

如果您可以使用CloudFlare的Zlib分支,直接使用flate2可能会提高一些速度。不过,我还没有测试过。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接