我正在开发一个 Python 库,该库对长位字符串执行大量按位运算,并且我想找到一种能够最大限度地提高其速度的位字符串类型。我已经尝试过内置的 Python int 类型、numpy、bitstring和bitarray,令人惊讶的是,Python int 在按位运算方面似乎更胜一筹。我用谷歌搜索的所有内容都说 numpy 对于像这样的矢量化操作应该更快。我是否以某种方式使用了 numpy 错误?是否有另一个我可以使用的 Python 库实际上改进了 Python 的内置 int 类型?
from timeit import timeit
import random
size = 10000
def int_to_bits(i):
result = []
for _ in range(size):
result.append(i % 2)
i >>= 1
return result
x = random.randrange(2**size)
y = random.randrange(2**size)
print(x.bit_length(), y.bit_length())
x_bits = int_to_bits(x)
y_bits = int_to_bits(y)
t = timeit(
stmt='a & b',
setup='a = %d; b = %d' % (x, y)
)
print("raw ints:", t)
t = timeit(
stmt='a & b',
setup=('import numpy;'
'a = numpy.array(%r, dtype=int);'
'b = numpy.array(%r, dtype=int)') % (x_bits, y_bits)
)
print('numpy int array:', t)
t = timeit(
stmt='a & b',
setup=('import numpy;'
'a = numpy.array(%r, dtype=bool);'
'b = numpy.array(%r, dtype=bool)') % (x_bits, y_bits)
)
print('numpy bool array:', t)
t = timeit(
stmt='a & b',
setup=('import numpy;'
'a = numpy.packbits(%r);'
'b = numpy.packbits(%r)') % (x_bits, y_bits)
)
print('numpy packed bits:', t)
t = timeit(
stmt='a & b',
setup=('import bitstring;'
'a = bitstring.BitString(%r);'
'b = bitstring.BitString(%r)') % (x_bits, y_bits)
)
print('bitstring:', t)
t = timeit(
stmt='a & b',
setup=('import bitarray;'
'a = bitarray.bitarray(%r);'
'b = bitarray.bitarray(%r)') % (x_bits, y_bits)
)
print('bitarray:', t)
结果:
10000 10000
raw ints: 0.29606562735373115
numpy int array: 7.400762747057885
numpy bool array: 1.1108355715984288
numpy packed bits: 1.3064737574273284
bitstring: 380.9796937642803
bitarray: 1.4451143449501842
编辑:
关于 Python ints/longs 上的单个操作如何与整个 numpy 位数组上的向量操作相当,似乎有很多困惑。一个 10,000 位的 Python int/long 值,当被视为位掩码时(使用 & 运算符,就像我们可以在 C/C++ 中使用 ints 或 longs 一样)与长度为 10,000 的 numpy bool 数组直接可比,因为它们都包含相同数量的位,尽管以 2 种不同的方式表示。我尝试过的其他表示 10,000 位的方法也是如此,包括使用 numpy 压缩位数组、numpy int 数组和来自其他库的位数组/字符串类型。它们都是可比较的,因为它们都在相同的位序列上计算相同的函数。这里重要的是我可以表示所有 10,000 位,并且我可以对它们执行按位运算。
如果您仍然对 Python int/long 值如何存储与 numpy bool 数组或 numpy 二进制值 int 数组相同的信息感到困惑,请参考int_to_bits
上面代码中的函数;它演示了如何从 Python int/long 中提取位,这表明在两个 10,000 位 int 上执行 & 操作与在 10,000 个布尔值的列表或数组上逐个元素执行它基本相同。