我试图对我的外部排序算法进行一些测试,我认为我应该生成大量的随机数并将它们放入文件中。
我是这样做的:
import tempfile, random
nf = tempfile.NamedTemporaryFile(delete=False)
i = 0
while i < 1000:
j = 0
buf = ''
while j < 1000:
buf += str(random.randint(0, 1000))
j += 1
nf.write(buf)
i += 1
我想,我应该通过减少文件IO操作来加快生成过程,所以我使用buf
来存储尽可能多的数字,然后将buf写入文件。
问题:
我仍然感觉到,生成和编写过程很慢。
我出错了吗?
修改
在C ++中,我们可以简单地将int
或float
写入<<
文件,而不将converting them
写入字符串。
那么我们可以在Python中做同样的事情吗?我的意思是将整数写入文件而不将其转换为str。
答案 0 :(得分:7)
操作系统已针对此类I / O操作进行了优化。因此,您可以直接将数字写入文件并获得非常好的速度:
import tempfile, random
with tempfile.NamedTemporaryFile(delete=False) as nf:
for _ in xrange(1000000): # xrange() is more efficient than range(), in Python 2
nf.write(str(random.randint(0, 1000)))
实际上,只有在大小优化的文件缓冲区已满时,才会将数字写入磁盘。问题中的代码和上面的代码在我的机器上同时进行。所以,我建议使用我更简单的代码并依赖操作系统的内置优化。
如果结果适合内存(100万个数字就是这种情况),那么你可以通过创建最终字符串然后一次性编写来保存一些I / O操作:
with tempfile.NamedTemporaryFile(delete=False) as nf:
nf.write(''.join(str(random.randint(0, 1000)) for _ in xrange(1000000)))
第二种方法在我的计算机上快了30%(2.6秒而不是3.8秒),这可能要归功于单次写入调用(而不是一百万write()
次调用 - 实际磁盘写入可能少得多)
你的问题的“许多大写”方法落在中间(3.1秒)。但是它可以改进:它更清晰,更Pythonic写这样:
import tempfile, random
with tempfile.NamedTemporaryFile(delete=False) as nf:
for _ in xrange(1000):
nf.write(''.join(str(random.randint(0, 1000)) for _ in xrange(1000)))
这个解决方案相当于原始问题中的代码(比我原来的2.6秒,而不是3.8秒)。
总之,上面的第一个简单方法对您来说可能足够快。如果不是,并且整个文件可以适合内存,第二种方法既快速又简单。否则,你最初的想法(更少的写入,更大的块)是好的,因为它与“单一写入”方法一样快,并且仍然非常简单,如上所述。
答案 1 :(得分:3)
不要在循环中使用字符串连接。请改用str.join
。
CPython实现细节:如果s和t都是字符串,某些Python实现(如CPython)通常可以对s = s + t或s + = t形式的赋值执行就地优化。如果适用,此优化使得二次运行时间的可能性大大降低。此优化依赖于版本和实现。对于性能敏感的代码,最好使用str.join()方法,该方法确保跨版本和实现的一致的线性串联性能。
您的代码如下所示:
buf = ''.join(str(random.randint(0, 1000)) for j in range(1000))
请注意,由于您尚未指定分隔符,因此它将如下所示:
3847018274193258124003837134....
如果您希望数字(例如)以逗号分隔,请将''
更改为','
。
我也认为你不需要缓冲自己,因为写入文件应该已经缓冲了。
答案 2 :(得分:2)
如果你只需要生成一些随机数并且你在Linux下,请尝试shell命令
for i in {1..1000000}; do echo $[($RANDOM % 1000)]; done > test.in
好的,我在下面测试这段代码,完成后需要大约5秒钟
import tempfile, random
nf = tempfile.NamedTemporaryFile(delete=False)
for i in xrange(0, 1000000):
nf.write(str(random.randint(0, 1000)))
答案 3 :(得分:1)
我不确定Python,但+ =通常是一个昂贵的操作,因为它将字符串复制到新的内存。
使用您加入的某些字符串构建器或数组可能要快得多。
答案 4 :(得分:1)
喜欢这个
import random
import struct
with open('binary.dat','wb') as output:
for i in xrange(1000000):
u = random.randint(0,999999) # number
b = struct.pack('i', u) # bytes
output.write(b)
这将创建400万字节的数据。 100万个4字节值。
您可以在struct
阅读以及各种打包选项:http://docs.python.org/library/struct.html。
答案 5 :(得分:-2)
做一百万件事情会相对缓慢。此外,根据您想要数字的随机性,您可能希望投资更强大的随机整数生成器。这是个人的最爱:http://en.wikipedia.org/wiki/Mersenne_twister