Python 一种生成大型随机字节数组的有效方法
我需要创建一个特定大小的大bytearry,但在运行之前还不知道它的大小。字节需要相当随机。字节数组大小可能小到几KBs,但大到几MB。我不想逐字节迭代。这太慢了--我需要类似于numpy.random的性能。但是,我没有可用于此项目的numpy模块。在标准python安装中有什么东西可以做到这一点吗?还是我需要 对于那些询问时间的人:Python 一种生成大型随机字节数组的有效方法,python,random,bytearray,Python,Random,Bytearray,我需要创建一个特定大小的大bytearry,但在运行之前还不知道它的大小。字节需要相当随机。字节数组大小可能小到几KBs,但大到几MB。我不想逐字节迭代。这太慢了--我需要类似于numpy.random的性能。但是,我没有可用于此项目的numpy模块。在标准python安装中有什么东西可以做到这一点吗?还是我需要 对于那些询问时间的人: >>> timeit.timeit('[random.randint(0,128) for i in xrange(1,100000)]',s
>>> timeit.timeit('[random.randint(0,128) for i in xrange(1,100000)]',setup='import random', number=100)
35.73110193696641
>>> timeit.timeit('numpy.random.random_integers(0,128,100000)',setup='import numpy', number=100)
0.5785652013481126
>>>
只包括numpy有什么不对?无论如何,这将创建一个随机N位整数:
import random
N = 100000
bits = random.getrandbits(N)
因此,如果需要查看第j位的值是否已设置,可以执行位&(2**j)=(2**j)
编辑:他要求的是字节数组而不是位数组。Ned的答案更好:your_byte_array=bytearray((随机.getrandbits(8)表示x范围(N)中的i))
在itertools中可能有一些东西可以帮助我们,总是有
我的计时表明,这比xrange(1100000)中的i的随机.randint(0128)大约快五倍
bytearray(os.urandom(1000000))
这似乎可以按照您的需要快速执行,事实上,我的计时比您的numpy更好(尽管我们的机器可能会大不相同):
有几种可能,有些比
lambda n:bytearray(map(random.getrandbits,(8,)*n))
我在单元测试中使用了上述方法,虽然速度足够快,但可以更快吗
使用itertools:
lambda n:bytearray(itertools.imap(random.getrandbits,itertools.repeat(8,n)))
itertools和struct每次迭代生成8字节
lambda n:(b''.join(map(struct.Struct("!Q").pack,itertools.imap(
random.getrandbits,itertools.repeat(64,(n+7)//8)))))[:n]
基于b''的任何内容。join
将使用临时对象填充最终bytearray消耗的内存的3-7倍,因为它在将所有子字符串连接在一起之前会对它们进行排队,并且python对象具有足够的内存
使用专用函数生成大数据块可以提供更好的性能,并避免占用内存
import random,itertools,struct,operator
def randbytes(n,_struct8k=struct.Struct("!1000Q").pack_into):
if n<8000:
longs=(n+7)//8
return struct.pack("!%iQ"%longs,*map(
random.getrandbits,itertools.repeat(64,longs)))[:n]
data=bytearray(n);
for offset in xrange(0,n-7999,8000):
_struct8k(data,offset,
*map(random.getrandbits,itertools.repeat(64,1000)))
offset+=8000
data[offset:]=randbytes(n-offset)
return data
这将以180 MB/s的速度生成伪随机数据。(没有硬件AES加速,单核)这只是上述纯python代码速度的5倍
补遗
有一个纯python加密库正在等待编写。将上述技术与hashlib和流密码技术结合在一起看起来很有希望。这里有一个提示,一个快速字符串异或(42MB/s)
打开
/dev/uradom
?Python提供了一个到/dev/uradom的可移植接口:参见我的(第二个)答案。这很好。我是否错过了将long转换为bytearray或bytebuffer的一些明显的方法?无法使用NumPy,因为我的环境限制我只能使用数量非常有限的外部包。@Paul-Ned有解决方案。对不起,我的阅读理解能力很差,把它误读成了位数组。如果你想把它作为一个单行程序,你可以用bytearray((random.getrandbits(8)for i in xrange(N))KISS原则:不要导入你实际上不需要的包。查看我的计时。我正在寻找大约30-100倍的加速。在我编写的机器上,使用random.getrandbits(8)
作为random.randint的替代品(0,256)
的速度大约是6倍。我想补充一点,随机模块生成伪随机数据的速度比os.urandom
快,至少在Linux上是这样。----------------------------------------In[102]:timeit.timeit(lambda:bytearray(os.urandom(2**16)),number=100)
Out[102]:0.03401689900783822
-------------------------------------在[103]中:timeit.timeit(lambda:(random.getrandbits(8*2**16)).to_字节(2**16,sys.byteorder),number=100)
输出[103]:0.01772290701046586
操作系统随机()
可以在Linux上阻塞。请参阅。
lambda n:(b''.join(map(struct.Struct("!Q").pack,itertools.imap(
random.getrandbits,itertools.repeat(64,(n+7)//8)))))[:n]
import random,itertools,struct,operator
def randbytes(n,_struct8k=struct.Struct("!1000Q").pack_into):
if n<8000:
longs=(n+7)//8
return struct.pack("!%iQ"%longs,*map(
random.getrandbits,itertools.repeat(64,longs)))[:n]
data=bytearray(n);
for offset in xrange(0,n-7999,8000):
_struct8k(data,offset,
*map(random.getrandbits,itertools.repeat(64,1000)))
offset+=8000
data[offset:]=randbytes(n-offset)
return data
import os
seed=os.urandom(32)
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
backend = default_backend()
cipher = Cipher(algorithms.AES(seed), modes.CTR(b'\0'*16), backend=backend)
encryptor = cipher.encryptor()
nulls=b'\0'*(10**5) #100k
from timeit import timeit
t=timeit(lambda:encryptor.update(nulls),number=10**5) #1GB, (100K*10k)
print("%.1f MB/s"%(1000/t))
def xor(a,b):
s="!%iQ%iB"%divmod(len(a),8)
return struct.pack(s,*itertools.imap(operator.xor,
struct.unpack(s,a),
struct.unpack(s,b)))