【问题标题】:Put python long integers into memory without any space between them将python长整数放入内存中,它们之间没有任何空格
【发布时间】:2016-09-02 13:43:36
【问题描述】:

我想将许多大长整数放入内存中,它们之间没有任何空格。如何在 linux 中使用 python 2.7 代码做到这一点?

大长整数都使用相同的位数。总共有大约 4 GB 的数据。保留几位空间以使每个长整数在内存中使用 8 位的倍数是可以的。我想稍后对它们进行按位运算。

到目前为止,我使用的是 python 列表。但我不确定这是否在整数之间留下内存空间。 ctypes 可以帮忙吗?

谢谢。

旧代码使用bitarray (https://pypi.python.org/pypi/bitarray/0.8.1)

import bitarray
data = bitarray.bitarray()
with open('data.bin', 'rb') as f:
    data.fromfile(f)
result = data[:750000] & data[750000:750000*2]

这行得通,并且位数组在内存中没有间隙。但是,在计算机上,bitarray 按位运算比原生 python 的长整数按位运算慢约 6 倍。在旧代码中切片位数组并在新代码中访问列表中的元素使用大致相同的时间。

较新的代码:

import cPickle as pickle

with open('data.pickle', 'rb') as f:
    data = pickle.load(f)
# data is a list of python's (long) integers
result = data[0] & data[1]

麻木: 在上面的代码中。 result = data[0] & data[1] 创建一个新的长整数。 Numpy 有 numpy.bitwise_and 的 out 选项。这将避免创建一个新的 numpy 数组。然而,numpy 的 bool 数组似乎每个 bool 使用一个字节,而不是每个 bool 一个位。而将 bool 数组转换为 numpy.uint8 数组就可以避免这个问题,但是计算设置位的个数太慢了。

python 的原生数组无法处理大的长整数:

import array
xstr = ''
for i in xrange(750000):
    xstr += '1'
x = int(xstr, 2)

ar = array.array('l',[x,x,x])
# OverflowError: Python int too large to convert to C long

【问题讨论】:

  • 有一些示例代码来说明您想要实现的目标吗?
  • 为什么要关心内存布局?您是否打算与另一个进程共享该内存?
  • 嗯。我猜该列表的内存效率低于位数组。有很多数据。实际程序使用多处理库,不修改数据... 第一版程序多次从硬盘读取数据。那个超级慢。
  • 你不能在数据上处理一个滑动窗口吗?例如data1 = bytearray(93750);data2 = bytearray(93750);f.readinto(data1);f.readinto(data2);result = map(operator._and, data1, data2)。这假设这些位被打包到文件中。

标签: python memory ctypes long-integer


【解决方案1】:

可以使用array模块,例如:

import array
ar = array('l', [25L, 26L, 27L])
ar[1]  # 26L

【讨论】:

  • 我试过了,但在我的情况下长整数太大了。谢谢你的建议。
【解决方案2】:

空间效率低下的主要原因是 Python long 的内部结构。假设是 64 位平台,Python 只使用 32 位中的 30 位来存储一个值。 gmpy2 库提供对GMP(GNU 多精度算术库)的访问。 gmpy2.mpz 类型的内部结构使用所有可用位。这是存储 750000 位值的大小差异。

>>> import gmpy2
>>> import sys
>>> a=long('1'*750000, 2)
>>> sys.getsizeof(a)
100024
>>> sys.getsizeof(gmpy2.mpz(a))
93792

使用 ``gmpy2.mpz` 的 & 操作也明显更快。

$ python -m timeit -s "a=long('A'*93750,16);b=long('7'*93750)" "c=a & b"
100000 loops, best of 3: 7.78 usec per loop
$ python -m timeit -s "import gmpy2;a=gmpy2.mpz('A'*93750,16);b=gmpy2.mpz('7'*93750)" "c=a & b"
100000 loops, best of 3: 4.44 usec per loop

如果您的所有操作都在原地进行,gmpy2.xmpz 类型允许在不创建新实例的情况下更改实例的内部值。只要所有操作都是即时的,它就会更快。

$ python -m timeit -s "import gmpy2;a=gmpy2.xmpz('A'*93750,16);b=gmpy2.xmpz('7'*93750)" "a &= b"
100000 loops, best of 3: 3.31 usec per loop

免责声明:我维护 gmpy2 库。

【讨论】:

  • 这很好。我想我会更改代码以使用 gmpy2。是否可以跨多个进程(多处理库)共享 gmpy.mpz 而无需在内存中复制?
  • 在进程之间共享 Python 对象很困难。您可能想阅读stackoverflow.com/questions/1268252/…
猜你喜欢
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 2015-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多