如何生成100万个随机整数并写入文件?
我在测试我的外部排序算法时,想生成大量随机数字并把它们放进一个文件里。
这是我做的方式:
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
我想,应该通过减少文件输入输出操作来加快生成过程,所以我用buf
来存储尽可能多的数字,然后再把这个buf写入文件。
问题:
不过我还是觉得,生成和写入的过程有点慢。
我是不是哪里搞错了?
编辑:
在C++中,我们可以直接用<<
把一个int
或float
写入文件,而不需要把它们转换
成字符串。
那么在Python中,我们能不能也这样做?我的意思是,能不能直接把一个整数写入文件,而不需要把它转换成字符串?
6 个回答
如果你只需要生成一些随机数字,并且你在使用Linux系统,可以试试这个命令
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)))
在循环中不要使用字符串拼接,建议使用 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....
如果你想让数字之间用逗号分隔,可以把 ''
改成 ','
。
我觉得你也不需要自己去缓存,因为写入文件的操作本身就已经有缓存了。
操作系统已经针对这种输入输出操作进行了优化。所以,你可以直接把数字写入文件,这样速度会非常快:
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)))
实际上,只有当优化后的文件缓存满了,数字才会被写入磁盘。在我的电脑上,问题中的代码和上面的代码所花的时间是一样的。所以,我建议你使用我更简单的代码,并依赖操作系统自带的优化。
如果结果可以放进内存(比如说一百万个数字),那么你确实可以通过先创建最终的字符串,然后一次性写入,来节省一些输入输出操作:
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秒)。不过,这种方法可以改进:用更清晰、更符合Python风格的方式来写会更好:
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秒)。
总的来说,上面提到的第一种简单方法可能对你来说已经足够快了。如果不够快,而且整个文件可以放进内存,那么第二种方法既非常快又简单。否则,你最初的想法(减少写入次数,增加写入块的大小)也是不错的,因为它的速度和“单次写入”方法差不多,而且用上面的方法写起来也很简单。