struct.pack 在 python 2.6 中使用 numpy 数组时要慢得多

struct.pack is much slower in python 2.6 when working with numpy arrays

基础问题

大家好。我相信我发现 python 2.6、struct.pack 和 numpy 数组存在问题。问题是当我 运行 使用 python 2.6 时,下面的代码非常慢(但是当我 运行 使用 python 2.7 或 2.5 时,它足够快)。

import numpy as np
import struct

x = np.mat(np.random.randint(0,3000,(1000,1000)))

z = struct.pack('<'+'H'*x.size,*np.asarray(x).reshape(-1).astype(int))

对于我正在处理的应用程序,我需要能够多次 运行 类似的东西,现在我唯一的选择是 运行 使用 python 2.6。我想问是否有更快的方法可以使用 python 2.6 来执行此操作,或者我是否应该花时间尝试让系统管理员为我安装 python 2.7 或 3.0。

至于为什么我需要能够在 python 2.6 上 运行 以及我是如何发现这行代码是问题的,请参见下文。

说来话长

我正在开展一个项目,我正在使用 python 修改一些输入到另一个程序中的文件,以便我可以 运行 在该程序上进行 Monte Carlo 模拟。一切进展顺利,我使用 python 3 编写了所有代码,确保它也能在 python 2.7 和 运行 我动力不足的计算机上的几个测试用例中正常工作。事情进展顺利。 运行 单个测试用例大约需要 30 秒。然后我将我的分析移植到我们拥有的服务器上,该服务器 faster/more 比我的笔记本电脑强大得多。

我在服务器上一切正常,但 运行 遇到了一个大问题。现在通过单个测试用例需要 30 分钟 运行。经过一番调查,我发现服务器只安装了 python 版本 2.6,我相信这就是问题所在。此外,我认为特别是以下行是问题

z = struct.pack('<'+'H'*x.size,*np.asarray(x).reshape(-1).astype(int))

其中x是一个numpy矩阵,numpy已经被导入为np,struct也被导入了。我认为这条线的原因如下。首先,当 运行 在 python 2.6 中使用此行时,我收到以下警告:

DeprecationWarning: struct integer overflow masking is deprecated

尽管我绝对确定我要打包的数组的内容落在无符号短整数的范围内。 运行 使用 python 2.7 和 3.5 的完全相同的代码我也没有收到弃用警告。

此外,我尝试了一个使用时间的简短测试。我在本地机器上使用 python 2.7 和 3.0 运行 以下代码并得到以下结果:

python3 -m timeit "import numpy as np;import struct;x=np.mat(np.random.randint(0,3200,(1000,1000)));z = struct.pack('<'+'H'*x.size,*np.asarray(x).reshape(-1).astype(int))"
10 loops, best of 3: 467 msec per loop

python2.7 -m timeit "import numpy as np;import struct;x=np.mat(np.random.randint(0,3200,(1000,1000)));z = struct.pack('<'+'H'*x.size,*np.asarray(x).reshape(-1).astype(int))"
10 loops, best of 3: 468 msec per loop

非常好。然后我尝试 运行 使用 python 2.6

python2.6 -m timeit "import numpy as np;import struct;x=np.mat(np.random.randint(0,3200,(1000,1000)));z = struct.pack('<'+'H'*x.size,*np.asarray(x).reshape(-1).astype(int))"
10 loops, best of 3: 34.4 sec per loop

这是荒谬的 7350% 时间增长...

我要问的问题是——有什么方法可以使用 python 2.6 来解决这个瓶颈,还是我应该让服务器的系统管理员升级到 python 3.5 还是 2.7?

为什么不完全避免使用 struct 模块,让 numpy 为您处理二进制转换?

例如:

import numpy as np

x = np.random.randint(0, 3200, (1000, 1000))
z = x.astype('<u2').tostring()

'<u2' 指定 little-endian (<) unsigned int (u) 16 位 (2)。它与 <H.

相同

只是为了证明它们是相同的:

z1 = x.astype('<u2').tostring()
z2 = struct.pack('<'+'H'*x.size,*np.asarray(x).reshape(-1).astype(int))
assert z1 == z2

对于计时(注意:这是在 python 2.7 上),numpy 版本快约 100 倍:

In [7]: %timeit x.astype('<u2').tostring()
100 loops, best of 3: 1.33 ms per loop

In [8]: %timeit struct.pack('<'+'H'*x.size,*np.asarray(x).reshape(-1).astype(int))
1 loops, best of 3: 118 ms per loop