Python - 在“字节"中对每个字节进行“异或"运算以最有效的方式 [英] Python - "xor"ing each byte in "bytes" in the most efficient way

查看:563
本文介绍了Python - 在“字节"中对每个字节进行“异或"运算以最有效的方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个bytes"对象和一个int"掩码,我想用我的掩码对所有字节进行异或.我对大字节"对象(~ 4096 KB)反复执行此操作.

I have a "bytes" object and an "int" mask, I want to do a xor over all the bytes with my mask. I do this action repeatedly over big "bytes" objects (~ 4096 KB).

这是我的代码,它可以很好地完成工作,只是它占用大量 CPU 并减慢我的脚本速度:

This is the code I have which does the work well, only it is very CPU intensive and slows down my script:

# '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 倍:

The best I could come up with is this, which is about 20 times faster:

# '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

P.S. if it is of any importance, I'm using Python 3.5

推荐答案

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

I don't think you can get much faster than your algorithm, using pure Python. (But Fabio Veronese's answer shows that's not true). You can shave off a tiny bit of time by doing the looping in a list comprehension, but then that list needs to be converted back into an array, and the array has to be converted to bytes, so it uses more RAM for a negligible benefit.

但是,您可以通过使用 Numpy 使速度大大.这是一个简短的演示.

However, you can make this much faster by using Numpy. Here's a short demo.

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 进行测试.

Tested using Python 3.6.0 on an old single core 32 bit 2GHz machine running on Linux.

我刚刚用 datasize = 4000000 跑了一次,do_mask_numpy 用了 0.0422 秒.

I just did a run with datasize = 4000000 and do_mask_numpy took 0.0422 seconds.

这篇关于Python - 在“字节"中对每个字节进行“异或"运算以最有效的方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆