Python - "xor"以最有效的方式处理 "bytes"中的每个字节

标签 python performance

我有一个“bytes”对象和一个“int”掩码,我想用我的掩码对所有字节进行异或运算。 我对大“字节”对象(~ 4096 KB)重复执行此操作。

这是我的代码,它工作得很好,只是它非常占用 CPU 并且会减慢我的脚本:

# 'data' is bytes and 'mask' is int
bmask = struct.pack('!I', mask) # converting the "int" mask to "bytes" of 4 bytes 
a = bytes(b ^ m for b, m in zip(data, itertools.cycle(bmask)))

我能想到的最好的是这个,它快了大约 20 倍:

# 'data' is bytes and 'mask' is int
# reversing the bytes of the mask
bmask = struct.pack("<I", mask)
mask = struct.unpack(">I", bmask)[0]

# converting from bytes to array of "int"s
arr = array.array("I", data)

# looping over the "int"s
for i in range(len(arr)):
    arr[i] ^= mask

# must return bytes
a = bytes(arr)

我的问题是:

  1. 有没有更有效的方法来做到这一点(CPU-wize)?
  2. 是否有一种“更简洁”的方式来做到这一点(不影响性能)?

附言如果它很重要,我正在使用 Python 3.5

最佳答案

我不认为使用纯 Python 可以比您的算法快很多。 (但 Fabio Veronese 的回答表明这不是真的)。您可以通过在列表理解中进行循环来节省一点时间,但随后需要将该列表转换回数组,并且必须将数组转换为字节,因此它使用更多 RAM 的好处可以忽略不计.

但是,您可以使用 Numpy 使这大大更快。这是一个简短的演示。

from time import perf_counter
from random import randrange, seed
import array
import numpy as np

seed(42)

def timed(func):
    ''' Timing decorator '''
    def wrapped(*args):
        start = perf_counter()
        result = func(*args)
        stop = perf_counter()
        print('{}: {:.6f} seconds'.format(func.__name__, stop - start))
        return result
    wrapped.__name__ = func.__name__
    wrapped.__doc__ = func.__doc__
    return wrapped

@timed
def do_mask_arr1(data, mask):
    arr = array.array("I", data)
    # looping over the "int"s
    for i in range(len(arr)):
        arr[i] ^= mask
    return arr.tobytes()

@timed
def do_mask_arr2(data, mask):
    arr = array.array("I", data)
    return array.array("I", [u ^ mask for u in arr]).tobytes()

@timed
def do_mask_numpy(data, mask):
    return (np.fromstring(data, dtype=np.uint32) ^ mask).tobytes()

@timed
def make_data(datasize):
    ''' Make some random bytes '''
    return bytes(randrange(256) for _ in range(datasize))

datasize = 100000
mask = 0x12345678
data = make_data(datasize)

d1 = do_mask_arr1(data, mask)
d2 = do_mask_arr2(data, mask)
print(d1 == d2)

d3 = do_mask_numpy(data, mask)
print(d1 == d3)

典型输出

make_data: 0.751557 seconds
do_mask_arr1: 0.026865 seconds
do_mask_arr2: 0.025110 seconds
True
do_mask_numpy: 0.000438 seconds
True

在运行 Linux 的旧单核 32 位 2GHz 机器上使用 Python 3.6.0 进行测试。

我刚刚用 datasize = 4000000 运行了一次,do_mask_numpy 花了 0.0422 秒。

关于Python - "xor"以最有效的方式处理 "bytes"中的每个字节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46540337/

相关文章:

python /Tkinter : Stretch an image horizontally?

python - 多重索引和日期时间

c - 具有 1 个线程的 OpenMP 比顺序版本慢

javascript - Map.has 与 Map.get 之间的性能差异

java GC CMS-initial-mark 减慢对高负载 tomcat 生产服务器的查询

python - 如何从内存中保存webkit页面图片资源?

python - Windows - Pycharm - 安装python打包工具失败

python - 在 Python 中是否可以声明必须重写该方法?

java - 在 64 位 Java 中使用 long 而不是 int 有好处吗

mysql - 带排序的 SQL 查询