慢速按位操作
我正在研究一个对长位字符串执行大量按位操作的Python库,并且我想找到一个能够最大化速度的位串类型。 我尝试了内置的Python int类型,numpy,bitstring和bitarray,令人惊讶的是,当涉及到按位操作时,Python ints似乎赢得了双手。 我用Google搜索的所有内容都表示,对于像这样的矢量化操作,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位数组上的向量操作相比较的混淆。 当作为位掩码处理时(使用&运算符就像我们可以在C / C ++中使用整数或长整数一样),一个10,000位的Python int / long值可以直接与长度为10,000的numpy bool数组进行比较,因为它们都包含相同数量的比特,尽管以2种不同的方式表示。 对于表示我尝试的10,000位的其他方式也是如此,包括使用numpy打包位数组,numpy int数组和其他库中的位数组/字符串类型。 它们都是可比较的,因为它们都在相同的位序列上计算相同的功能。 这里重要的是,我可以表示所有10,000位,并且我可以对它们执行按位操作。 如果任何人都可以建议一种更有效的方法来表示允许使用按位运算符(&,|和〜)的长固定长度位序列,那就是我正在寻找的。
如果您仍然对Python int / long值如何将相同信息存储为numpy bool数组或numpy二进制值int数组int_to_bits
,请参阅上面代码中的int_to_bits
函数; 它演示了如何从Python int / long中提取位,这表明在两个10,000位整数上执行&操作基本上与在10,000个布尔值的列表或数组上执行元素一样。
据我所知,内置的Python 3 int
是您测试的选项中唯一一个计算一次超过一个字节的&
的块。 (我还没有完全弄清楚这个操作的NumPy源代码中的所有内容,但是看起来好像它没有优化来以大于dtype的块来计算它。)
bitarray
逐字节地进行, bitstring
来源逐字节地进行,并且做了一些事情,通过Cython搞砸了其获得速度的尝试,使其成为迄今为止最慢的。 相比之下,根据编译时参数PYLONG_BITS_IN_DIGIT
的值, int
操作可以使用15位或30位数字。 我不知道哪个设置是默认的。
您可以通过使用打包表示和更大的dtype来加速NumPy尝试。 看起来在我的机器上,32位dtype运行速度最快,击败Python整数; 我不知道你的设置是什么样的。 我得到了每种格式的10240位值的测试
>>> timeit.timeit('a & b', 'import numpy; a = b = numpy.array([0]*160, dtype=num
py.uint64)')
1.3918750826524047
>>> timeit.timeit('a & b', 'import numpy; a = b = numpy.array([0]*160*8, dtype=n
umpy.uint8)')
1.9460716604953632
>>> timeit.timeit('a & b', 'import numpy; a = b = numpy.array([0]*160*2, dtype=n
umpy.uint32)')
1.1728465435917315
>>> timeit.timeit('a & b', 'a = b = 2**10240-1')
1.5999407862400403
你试图测试什么 - 这些矢量操作呢? 你只是试图比较1操作的速度,并且普通的python会赢得'因为它不必设置numpy数组或bitarrays。
如何尝试跟随?
x = np.array([random.randrange(2**31)]*1000)
y = np.array([random.randrange(2**31)]*1000)
%timeit x & y # in ipython
%timeit [ a & b for (a,b) in zip(x,y)] # even though x and y are numpy arrays, we are iterating over them - and not doing any vector operations
有趣的是,如果
xxx = [random.randrange(2**31)] * 1000
yyy = [random.randrange(2**31)] * 1000
接着
%timeit [a & b for (a,b) in zip(xxx,yyy)]
纯粹的python列表,迭代它们比在numpy数组上迭代更快..有点直观。 不知道为什么。
同样,你可以尝试比特串和比特串
这是你在看什么?
链接地址: http://www.djcxy.com/p/75007.html