我需要生成10GB的随机数据。你知道吗
我编写了下面的python脚本,通过将包含随机长度的可打印ASCII字符的字符串写入文件的每一行来生成所需的字节数
它需要3个命令行参数。 1) 大小 2) 字符串的最小长度(可选参数,默认为4) 3) 字符串的最大长度(可选参数,默认为10)
这个程序既不使用内存也不执行大量IO操作。我可以使用什么策略来增加每单位时间写入的字节数。你知道吗
import random
import sys
K_SIZE = 1000
class Generator:
def __init__(self,low=4,high=10):
self.table = {i:chr(i) for i in range(33,127)}
self.low = low
self.high = high
def create_n_bytes(self,total_bytes):
bytes_created = 0
"""Hack at the moment, this condition will fail only after more than n bytes are
written """
while bytes_created < total_bytes:
bytes_to_create = random.randint(self.low,self.high)
bytes_created = bytes_created+bytes_to_create+1
word=[""]*bytes_to_create
for i in range(bytes_to_create):
word[i] = self.table[random.randint(33,126)]
text = "".join(word)
#print(str(hash(text))+"\t"+text)
print(text)
def get_file_size_from_command_line():
size = sys.argv[1]
return size
def get_min_word_len_from_command_line():
if len(sys.argv) > 2:
low = sys.argv[2]
return int(low)
def get_max_word_len_from_command_line():
if len(sys.argv) > 3:
high = sys.argv[3]
return int(high)
def get_file_size_in_bytes(size):
multiplier = 1
size_unit = size[-1]
if size_unit == 'M' or size_unit == 'm':
multiplier = K_SIZE*K_SIZE
elif size_unit == 'K' or size_unit == 'k':
multiplier = K_SIZE
elif size_unit == 'G' or size_unit == 'g':
multiplier = K_SIZE*K_SIZE*K_SIZE
elif size_unit in ('0','1','2','3','4','5','6','7','8','9'):
multiplier = 1
else:
print("invalid size")
exit()
total_bytes = 0
if multiplier == 1:
total_bytes = int(size)
else:
total_bytes = multiplier*int(size[:len(size)-1])
return total_bytes
def main():
if len(sys.argv) == 2:
gen = Generator()
elif len(sys.argv) == 3:
gen = Generator(get_min_word_len_from_command_line())
elif len(sys.argv) == 4:
gen = Generator(get_min_word_len_from_command_line(),get_max_word_len_from_command_line())
file_size = get_file_size_in_bytes(get_file_size_from_command_line())
gen.create_n_bytes(file_size)
if __name__== "__main__":
main()
首先,如果您要生成纯ASCII,并且需要它尽可能快,那么生成
bytes
可能比生成str
快。如果需要,可以随时调用decode('ascii')
,但更简单的是,直接将它们写入sys.stdout.buffer
或sys.stdout.buffer.raw
。你知道吗这意味着您可以摆脱将数字映射到
chr
值的表,只需从int中构造一个bytes
或bytearray
。(只要所有的值都在range(0, 128)
中,就可以保证得到相同的结果,但是只有一个函数调用内部有一个C循环,而不是Python循环中的函数调用。)另外,您可以只调用
random.choices(range(33, 127), k=N)
,然后将结果传递给bytes
构造函数,而不是构造一个由N个空字符串组成的列表,然后逐个替换它们。你知道吗正如Dillon Davis所指出的那样,当我们在进行时,
randint
相当慢;通过手动执行相同的逻辑,您可以快3-5倍。这在这里并不是很重要(我们正在做一个randint
来换取几百个choices
),但仍然可以修复它。你知道吗所以,把这些放在一起:
另外,尝试用PyPy而不是CPython运行相同的代码。可能快5%,也可能快20倍。你知道吗
如果您需要挤出更多的性能,所有常用的微优化技巧可能都适用于这里,比如在局部变量中隐藏
randint
和choices
和sys.stdout.buffer
(或者sys.stdout.buffer.write
两种方法都可以)。你知道吗如果它的速度还远远不够快,那么您需要改变一些事情,一次生成更多的字节。你知道吗
这意味着传递一个更大的
total_bytes
值,但也可能意味着在NumPy中拖拽:现在,如何将其分解为
low
到high
字节的单词?我想不出什么真正聪明的方法,但是一个愚蠢的循环应该比上面所有的代码都快:这一次结束得太早,而不是走得太远。但不管你做什么,你显然都要处理这个问题,不管你怎么做,你都有可能准确地击中
total_bytes
,对吧?你知道吗(对
data
返回的memoryview
进行切片,而不是对数组进行切片并对其调用to_bytes()
,这有点不切实际,但是考虑到我们创建数组的方式,它保证可以执行相同的操作,并且可能会节省几微秒,因此可能值得使用注释。)如果我们不介意浪费内存,我们可以构建一个随机偏移量数组,保证足够大(但可能太大),然后将其用作索引数组:
对于1MB的数组来说,这里的加速比应该比1000字节这样的小数组要大得多(由于额外的分配,这对于绝对巨大的数组来说也可能是不好的),但是它确实值得测试。你知道吗
性能比较在很大程度上取决于您的平台(如果您不重定向到
/dev/null
或NUL
,则包括您要写入的终端)和您选择的参数。你知道吗使用默认值
low=4
、high=10
和total_bytes=1000
(我使用1010
表示NumPy失败),在我的笔记本电脑上运行(macOS、iTerm内的IPython、不重定向stdout、CPython 3.7.0和pypypy 3.5.2/5.10),下面是我的结果:randint
的我的版本:911µsrandom
的我的版本:909µsrandom.choices
):799µs如果减去最后一个,得到不同算法的实时间:
randint
的我的版本:407µsrandom
的我的版本:405µsrandom.choices
):295µs对于NumPy
randint
/cumsum
版本,我在另一台笔记本电脑上进行测试,但要针对原始的NumPy版本进行测试,stdout重定向到/dev/null:cumsum
版本:41µs所以,这是一个3倍的加速比,已经是27倍的加速比了,所以我们说的是大概80倍的加速比。但是写到一个终端会减慢速度,以至于挂钟的加速比只有5倍左右(如果你在Windows上,可能会更糟)。不过,还不错。你知道吗
相关问题 更多 >
编程相关推荐