Python解压相对性能?

2023-11-22

太长了;的python 中可用的各种压缩算法 gzip, bz2, lzma等,哪个有最好的减压表现?

完整讨论:

Python 3 有用于压缩/解压缩数据的各种模块包括gzip, bz2 and lzma. gzip and bz2此外,您还可以设置不同的压缩级别。

如果我的目标是平衡文件大小(/压缩比)和解压缩速度(压缩速度不是问题),那么哪个将是最佳选择?解压速度比文件大小更重要,但由于所讨论的未压缩文件每个约为 600-800MB(32 位 RGB .png 图像文件),而且我有十几个,我确实想要some压缩。

  • 我的用例是,我从磁盘加载十几个图像,对它们进行一些处理(作为 numpy 数组),然后在我的程序中使用处理后的数组数据。

    • 图像永远不会改变,我只需要在每次运行程序时加载它们。
    • 处理所需的时间与加载时间大致相同(几秒),因此我尝试通过保存处理后的数据来节省一些加载时间(使用pickle)而不是每次都加载原始的、未处理的图像。最初的测试很有希望 - 加载原始/未压缩的 pickled 数据花费了不到一秒的时间,而加载和处理原始图像则需要 3 或 4 秒 - 但正如前面提到的,文件大小约为 600-800MB,而原始 png 图像是仅5MB左右。因此,我希望可以通过以压缩格式存储选取的数据来在加载时间和文件大小之间取得平衡。
  • 更新:情况实际上比我上面描述的要复杂一些。我的应用程序使用PySide2,所以我可以访问Qt图书馆。

    • 如果我读取图像并使用转换为 numpy 数组pillow (PIL.Image),实际上我不需要做任何处理,但是将图像读入数组的总时间约为 4 秒。
    • 如果我使用QImage要读取图像,我必须对结果进行一些处理,以使其可用于我的程序的其余部分,因为它的字节顺序QImage加载数据 - 基本上我必须交换位顺序,然后旋转每个“像素”,以便 alpha 通道(显然是由 QImage 添加的)出现在最后而不是第一个。整个过程大约需要3.8秒,所以边际地比仅仅使用 PIL 更快。
    • 如果我保存numpy数组未压缩,然后我可以在 0.8 秒内将它们加载回来,因此是迄今为止最快的,但文件大小很大。
┌────────────┬────────────────────────┬───────────────┬─────────────┐
│ Python Ver │     Library/Method     │ Read/unpack + │ Compression │
│            │                        │ Decompress (s)│    Ratio    │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.7.2      │ pillow (PIL.Image)     │ 4.0           │ ~0.006      │
│ 3.7.2      │ Qt (QImage)            │ 3.8           │ ~0.006      │
│ 3.7.2      │ numpy (uncompressed)   │ 0.8           │ 1.0         │
│ 3.7.2      │ gzip (compresslevel=9) │ ?             │ ?           │
│ 3.7.2      │ gzip (compresslevel=?) │ ?             │ ?           │
│ 3.7.2      │ bz2 (compresslevel=9)  │ ?             │ ?           │
│ 3.7.2      │ bz2 (compresslevel=?)  │ ?             │ ?           │
│ 3.7.2      │ lzma                   │ ?             │ ?           │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.7.3      │ ?                      │ ?             │ ?           │  
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.8beta1   │ ?                      │ ?             │ ?           │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.8.0final │ ?                      │ ?             │ ?           │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.5.7      │ ?                      │ ?             │ ?           │
├────────────┼────────────────────────┼───────────────┼─────────────┤
│ 3.6.10     │ ?                      │ ?             │ ?           │
└────────────┴────────────────────────┴───────────────┴─────────────┘

示例 .png 图像:举个例子,以这个 5.0Mb png 图像,阿拉斯加海岸线的相当高分辨率的图像.

png/PIL 案例的代码(加载到numpy array):

from PIL import Image
import time
import numpy

start = time.time()
FILE = '/path/to/file/AlaskaCoast.png'
Image.MAX_IMAGE_PIXELS = None
img = Image.open(FILE)
arr = numpy.array(img)
print("Loaded in", time.time()-start)

在我使用 Python 3.7.2 的机器上,此负载大约需要 4.2 秒。

或者,我可以加载通过选择上面创建的数组生成的未压缩的 pickle 文件。

未压缩pickle负载情况的代码:

import pickle
import time

start = time.time()    
with open('/tmp/test_file.pickle','rb') as picklefile:
  arr = pickle.load(picklefile)    
print("Loaded in", time.time()-start)

在我的机器上,从这个未压缩的 pickle 文件加载大约需要 0.8 秒。


唾手可得的果实

numpy.savez_compressed('AlaskaCoast.npz', arr)
arr = numpy.load('AlaskaCoast.npz')['arr_0']

加载速度比基于 OIL 的代码快 2.3 倍。

It uses zipfile.ZIP_DEFLATED, see 保存压缩 docu.

您的 PIL 代码还有一个不需要的副本:array(img)应该asarray(img)。仅花费5%的慢加载时间。但优化后这将很重要,你必须记住哪些 numpy 运算符创建了副本。

快速减压

根据zstd 基准测试,当优化减压时lz4是一个不错的选择。只需将其插入 pickle 即可获得 2.4 倍的增益,并且仅比未压缩的 pickle 慢 30%。

import pickle
import lz4.frame

# with lz4.frame.open('AlaskaCoast.lz4', 'wb') as f:
#     pickle.dump(arr, f)

with lz4.frame.open('AlaskaCoast.lz4', 'rb') as f:
    arr = pickle.load(f)

基准测试

method                 size   load time
------                 ----   ---------
original (PNG+PIL)     5.1M   7.1
np.load (compressed)   6.7M   3.1
pickle + lz4           7.1M   1.3
pickle (uncompressed)  601M   1.0 (baseline)

加载时间是在 Python (3.7.3) 内测量的,使用的是在我的桌面上运行 20 多次的最小挂钟时间。根据偶尔的扫视top它似乎总是在单核上运行。

对于好奇的人:分析

我不确定 Python 版本是否重要,大多数工作应该在 C 库内部进行。为了验证这一点,我已经分析了pickle + lz4变体:

perf record ./test.py && perf report -s dso
Overhead  Shared Object
  60.16%  [kernel.kallsyms]  # mostly page_fault and alloc_pages_vma
  27.53%  libc-2.28.so       # mainly memmove
   9.75%  liblz4.so.1.8.3    # only LZ4_decompress_*
   2.33%  python3.7
   ...

大部分时间都花在 Linux 内核内部,page_fault以及与(重新)分配内存相关的内容,可能包括磁盘 I/O。金额高memmove看起来很可疑。每次新的解压块到达时,Python 可能都会重新分配(调整大小)最终数组。如果有人想仔细看看:python 和 perf 配置文件.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python解压相对性能? 的相关文章

随机推荐

  • Django 表命名约定。我可以改变它的行为吗?

    当 Django 创建表时 它会为它们提供 app class 形式的名称 我正在为 Django 安装改造一个不同的 但内容基本相似 数据库 我的表名称没有以 app 开头 我可以相应地重新创建我的数据库及其表 但我想看看 Django
  • 页面退出时弹出框

    我想做的是在页面退出或导航离开时创建一个弹出框 现在我有 我有两个问题 仅当您实际离开页面 刷新 新 URL 等时 它才会显示该框 如果您退出选项卡或浏览器 则不会弹出该框 无论您按哪个按钮 它只会将您发送到
  • 在关联文件中更改新版本的版本号(文档)

    我很想知道你们是如何处理的修改版本号对于新版本问题 如何处理关联文件 例如手册页等 中的版本号 该软件是使用 gnu 工具链构建的 因此 autoconf automake 等可用并用于应用程序的版本号 这样信息就可以被重用 git 被用作
  • Rails 中处理无效表单提交的正确方法

    我是 Rails 新手 不确定我是否同意我在一些教程中完成的工作方式 该问题与如何处理无效的表单提交有关 标准的做事方式似乎是 class ThingsController lt ApplicationController POST thi
  • 如何从 bash shell 脚本中的一行中提取单词[重复]

    这个问题在这里已经有答案了 我想从 bash 脚本中的句子中提取一个单词 它使用逗号和空格作为分隔符 ex date crossed 122 name foo userid 234567 sessionid 2233445axdfg5209
  • AFNetworking 2.0 POST 问题,Cocoa 错误 3840(JSON 文本未以数组开头...)

    我正在尝试在本地服务器上调用 api php 使用 MAMP 正在调用服务器端 api php 但 php 代码中的 POST 内容包含以下错误 Error Domain NSCocoaErrorDomain Code 3840 The o
  • 实现自定义 MVC 基本视图页面

    我正在尝试实现 MVC 自定义基本视图页面以 覆盖 User财产种类 这将使我的CustomPrincipal在任何视图中均可访问的类型 在网上搜索后 我发现Phil Haack 关于实现自定义基本视图页面的说明 我完全按照说明进行操作 但
  • Unicode字符插入数据库后变成问号

    当我将一些用 Unicode 编写的文本插入数据库时 它们变成了问号 数据库编码设置为UTF 8 还有什么可能是不正确的 当我检查 phpMyAdmin 时 只插入了问号 这是我用于连接数据库的代码 define DB HOST local
  • 如何在 Python 中创建和导入自定义模块

    如何将以下函数保存在一个 python 文件中 然后在另一个文件中使用它 文件A中的函数 def basic x print x B文件中的声明 basic some string A 创建一个包含所有模块的文件夹 例如 让我们使用 MyM
  • HTML.fromHtml 换行符消失

    我从 EditText 框中获取 Spanned Text 并使用 HTML toHtml 将其转换为 HTML 标记字符串 这很好用 我已经验证该字符串是正确的并且包含 br 在适当的位置 但是 当我需要使用 HTML fromHtml
  • 如何将 sqlite3 模块与 Electron 一起使用?

    我想使用开发桌面应用程序electron使用通过 npm 使用命令安装的 sqlite3 包 npm install save sqlite3 但它在电子浏览器控制台中给出以下错误 Uncaught Error Cannot find mo
  • 选择 .Net 的图表库 [关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我有一位客户需要将图表应用程序 很久以前是用 MFC 开发的 转换为 C 该应用程序显示大型网络 大量图形元素 并允许用户通过图形用户界面编辑 操作数据 我决定最好使用一个库 而不是
  • 如何将
    的箭头与 的内容垂直对齐

    我正在尝试垂直对齐附带的箭头
  • 改进猫鼬验证错误处理

    我有以下具有所需验证的架构 var mongoose require mongoose var validator require validator var userSchema new mongoose Schema email typ
  • Sharepoint CMS 与 UmbracoCMS

    我在一家大型地方政府组织工作 该组织即将开始使用 SharePoint 将我们老化的内部网替换为一个能歌善舞的协作网站 Intranet 的重点将是用 SharePoint 安装替换散布在整个组织中的随机文件 内容页面和文档 这将神奇地使所
  • 更改整个应用程序中的按钮样式

    我正在尝试将应用程序中按钮的所有 TextColor 更改为白色 并尝试将其设为粗体 但这并没有发生 我正在覆盖the android Widget Button我正在开发 Jelly Bean 4 1 2 我究竟做错了什么 清单中的主题定
  • 直接从 AlarmManager 唤醒服务

    In the https github com commonsguy cwac wakeful演示中 调用 OnAlarmReceiver 广播接收器 的 onReceive 方法来响应警报 onReceive 方法启动服务 使用了两种 I
  • 如何在 LINQ 中使用 whereif

    大家好 有人可以帮助我如何在 LINQ 中最好地使用 whereif IQueryable
  • 如何调用返回 data.table 中多行和多列的函数?

    我想调用 data table 中的一个函数来计算一组汇总统计信息 如下所示 summ stats lt function vec list Min min vec Mean mean vec S D sd vec Median media
  • Python解压相对性能?

    太长了 的python 中可用的各种压缩算法 gzip bz2 lzma等 哪个有最好的减压表现 完整讨论 Python 3 有用于压缩 解压缩数据的各种模块包括gzip bz2 and lzma gzip and bz2此外 您还可以设置