跳转到主要内容

简单、快捷的zip文件创建

项目描述

fastzip

该项目允许您高效地创建和组合zip文件。

“fastzip”中的“fast”是什么意思?

主要有两点

  1. 多线程压缩(DEFLATE),类似于
  2. 能够复制/合并zip文件而不重新压缩,类似于zipmerge

它也是纯Python,能够流式传输输入(不需要中央目录存在),并具有基于规则的压缩方法选择器,以避免增加小型文件的大小。

演示

与ZipFile相似的API

from pathlib import Path
from fastzip.write import WZip
with WZip(Path("out.zip")) as z:
    z.write(Path("a"))

合并现有文件

from fastzip.read import RZipStream
from fastzip.write import WZip
with WZip(Path("out.zip")) as z:
    for entry in RZipStream("zip1.zip").entries():
        z.enqueue_precompressed(*entry)
    for entry in RZipStream("zip2.zip").entries():
        z.enqueue_precompressed(*entry)

如果您想自定义线程数、压缩选择、归档中的文件名等,这些都是可能的。现在请查看源代码,但基本思路是

from io import BytesIO
from pathlib import Path
from fastzip.write import WZip
from fastzip.chooser import CompressionChooser

force_store = CompressionChooser(default="store")
with WZip(Path("out.zip"), threads=2, chooser=force_store) as z:
    z.write(Path("a"), archive_path=Path("inzipname"), synthetic_mtime=0, fobj=BytesIO(b"foo"))

基准测试

在8核和12核xeon上测试,对于足够大的工作负载,它分别能够使用约7.5和11个核心。有关瓶颈的更多信息,请参见下一节。

$ dd if=/dev/urandom of=a bs=1M count=512
512+0 records in
512+0 records out
536870912 bytes (537 MB, 512 MiB) copied, 2.17395 s, 247 MB/s

$ ./demo.sh
+ rm -f a.zip a1.zip a2.zip
+ cat a
+ /usr/bin/time zip -o a.zip a
  adding: a (deflated 0%)
11.35user 0.24system 0:11.60elapsed 99%CPU (0avgtext+0avgdata 2892maxresident)k
24inputs+1048752outputs (1major+205minor)pagefaults 0swaps
+ /usr/bin/time python -m zipfile -c a1.zip a
12.61user 0.44system 0:14.53elapsed 89%CPU (0avgtext+0avgdata 11360maxresident)k
0inputs+1048920outputs (0major+1623minor)pagefaults 0swaps
+ /usr/bin/time python -m fastzip -c -o a2.zip a
20.39user 0.56system 0:02.78elapsed 753%CPU (0avgtext+0avgdata 1079140maxresident)k
0inputs+1048968outputs (0major+149864minor)pagefaults 0swaps
+ ls -l a.zip a1.zip a2.zip
-rw-r--r-- 1 tim tim 537034782 Nov 16 13:47 a1.zip
-rw-r--r-- 1 tim tim 537037407 Nov 16 13:47 a2.zip
-rw-r--r-- 1 tim tim 536957493 Nov 16 13:01 a.zip

性能瓶颈

可能有多个。以下是一些我观察到的包括

  1. 慢速覆盖性能(在ext4上);这就是为什么WZip只以'xb'模式打开的原因。
  2. 小文件a. 慢速状态(即使在ramdisk上也为0.5mS)b. zlib.crc32不释放gil < 5KiB c. 小文件消耗了文件预算而没有取得很大进展(将顺序重新排序以在每个(file_budget-1)处有一个大文件可能会减少停滞
  3. 小的输出缓冲区(WZip现在以1MB打开)
  4. 查找(这需要刷新输出缓冲区)
  5. ThreadPoolExecutor巨锁(提交future需要获取两个锁,但其中一个是全局锁以检测解释器关闭?)
  6. Deflate块大小(较小的块意味着在中等大小文件上更好的并行性和更少的IO阻塞,但也需要调度更多的future、crc32调用和crc32_combine)。较大的块大小也意味着略好的压缩率。
  7. 垃圾回收(最近对并行性的调整似乎增加了垃圾回收的量)
  8. 混合使用deflate和zstd -- 虽然线程数量通常在它们之间共享,但在切换时仍可能出现停滞和溢出。

如果有疑问,请生成跟踪,并查找瓶颈(无论是空白时间,即没有进行有用的工作,还是除了压缩本身之外似乎需要很长时间的任何操作)。

示例跟踪

这个跟踪仅在中间标记为“acquire”的部分表现良好 -- 那里运行耗尽了一些资源,无法再排队更多数据,但压缩线程仍在全力工作。看似未标记的黄金事件是垃圾回收,你可以看到CPU图通常相当低。

Trace 1

这是中间部分的放大图,你可以更清楚地看到压缩线程很忙,I/O线程有一些空闲时间。MainThread中的差距意味着存在一些隐藏的工作。

Trace 2

未来计划(来自缺点)

近期问题

  1. 线程中发生的错误并不总是以明显的方式报告。
  2. 添加目录(而不是文件)是串行的。
  3. 文件必须是可MMAP的,在32位系统上这可能会耗尽进程地址空间。
  4. 存在一个打开文件预算,但没有正式的内存预算;输出未来可能大约缓冲最大的文件大小的两倍,在内存中。例如,上面的512MB文件峰值内存约为1GB。
  5. WZip太复杂,方法太多。这使得它难以重构和扩展。
  6. 验证不足(例如,重复的文件名,包含".."的文件名),并且对存档名代码是否稳固并不完全确定。

注意:API预计在1.0版本之前会改变几次;如果您要将依赖关系添加到此项目(例如,如果您使用假设的版本0.4,请确保指定>=0.4, <0.5)。

许可证

fastzip版权所有Tim Hatch,并使用MIT许可证许可。我在此仓库中向您提供代码,属于开源许可证。这是我的个人仓库;您从我那里获得的代码许可证来自我,而不是我的雇主。有关详细信息,请参阅LICENSE文件。

项目详情


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解更多关于安装软件包的信息。

源代码分布

fastzip-0.5.0.tar.gz (374.3 kB 查看哈希)

上传时间 源代码

构建分布

fastzip-0.5.0-py3-none-any.whl (19.8 kB 查看哈希)

上传时间 Python 3

由以下支持