Python 在文件中写入大量数据的最快方法

Python 在文件中写入大量数据的最快方法,python,performance,file,Python,Performance,File,我试图创建一个随机的实数、整数、字母数字、字母字符串,然后写入一个文件,直到文件大小达到10MB 代码如下 import string import random import time import sys class Generator(): def __init__(self): self.generate_alphabetical_strings() self.generate_integers() self.generate_

我试图创建一个随机的实数、整数、字母数字、字母字符串,然后写入一个文件,直到文件大小达到10MB

代码如下

import string
import random
import time
import sys


class Generator():
    def __init__(self):
        self.generate_alphabetical_strings()
        self.generate_integers()
        self.generate_alphanumeric()
        self.generate_real_numbers()

    def generate_alphabetical_strings(self):
        return ''.join(random.choice(string.ascii_lowercase) for i in range(12))

    def generate_integers(self):
        return ''.join(random.choice(string.digits) for i in range(12))

    def generate_alphanumeric(self):
        return ''.join(random.choice(self.generate_alphabetical_strings() +
                                     self.generate_integers()) for i in range(12))

    def _insert_dot(self, string, index):
        return string[:index].__add__('.').__add__(string[index:])


    def generate_real_numbers(self):
        rand_int_string = ''.join(random.choice(self.generate_integers()) for i in range(12))
        return self._insert_dot(rand_int_string, random.randint(0, 11))


from time import process_time
import os

a = Generator()

t = process_time()
inp = open("test.txt", "w")
lt = 10 * 1000 * 1000
count = 0
while count <= lt:
    inp.write(a.generate_alphanumeric())
    count += 39
inp.close()

elapsed_time = process_time() - t
print(elapsed_time)
导入字符串
随机输入
导入时间
导入系统
类生成器():
定义初始化(自):
self.generate_字母字符串()
self.generate_integers()
self.generate_字母数字()
self.generate_real_numbers()
def生成字母顺序字符串(自):
返回“”。范围(12)内的i的join(random.choice(string.ascii_小写)
def生成_整数(自):
返回“”。范围(12)内的i的join(random.choice(string.digits))
def生成字母数字(自身):
返回“”。join(random.choice(self.generate_字母顺序的_字符串)()+
为范围(12)内的i生成_整数()
定义插入点(自身、字符串、索引):
返回字符串[:index]。\uuuuu add\uuuuu('..)。\uuuuu add\uuuuuu(字符串[index:]))
def生成实数(自身):
rand_int_string=''.join(random.choice(self.generate_integers())用于范围(12)中的i)
返回self.\u插入点(rand\u int\u字符串,random.randint(0,11))
从时间导入过程\u时间
导入操作系统
a=发电机()
t=过程时间()
inp=open(“test.txt”、“w”)
lt=10*1000*1000
计数=0

当count时,你实际上创造了数十亿个物体,然后很快就扔掉了。在这种情况下,最好直接将字符串写入文件,而不是将它们与
'.join()

连接起来。观察到“缓慢”的两个主要原因是:

  • 您的while循环很慢,它有大约一百万次迭代
  • 您没有正确使用I/O缓冲。不要进行太多的系统调用。目前,您正在调用
    write()
    大约一百万次
首先在Python数据结构中创建数据,并只调用一次
write()

这是更快的:

t0 = time.time()
open("bla.txt", "wb").write(''.join(random.choice(string.ascii_lowercase) for i in xrange(10**7)))
d = time.time() - t0
print "duration: %.2f s." % d
输出:
持续时间:7.30秒。

现在,程序将大部分时间用于生成数据,即
随机
数据。通过将
random.choice(string.ascii\u小写)
替换为例如
“a”
,您可以很容易地看到这一点。然后在我的机器上测得的时间下降到1秒以下

如果您想更进一步了解您的计算机在写入磁盘时的速度,请使用Python最快的(?)方法在写入磁盘之前生成更大的数据:

>>> t0=time.time(); chunk="a"*10**7; open("bla.txt", "wb").write(chunk); d=time.time()-t0; print "duration: %.2f s." % d
duration: 0.02 s.

main calls
generate_字母数字
下的while循环,它从由12个ascii字母和12个数字组成的(新随机生成的)字符串中选择几个字符。这基本上与随机选择一个随机字母或一个随机数字12次相同。这是你的主要瓶颈。此版本将使您的代码快一个数量级:

def generate_alphanumeric(self):
    res = ''
    for i in range(12):
        if random.randrange(2):
            res += random.choice(string.ascii_lowercase)
        else:
            res += random.choice(string.digits)
    return res

我相信这是可以改进的。我建议你带上你的探查器转一转。

你的程序花在哪里的时间?@MartijnPieters我用Java尝试了同样的代码,花了约0.93秒。Java程序写入磁盘。完成此过程后,我手动检查了文件的大小。正确使用IO缓冲意味着什么?您正在写入磁盘。写入磁盘是一个复杂的物理和逻辑过程。它涉及很多机械和控制。告诉磁盘“这里,这是10 MB的数据,写吧!”比告诉它数百万次“这里,这是1字节的数据,写吧!”要快得多。因此,操作系统有一种机制,可以在实际将数据保存到磁盘之前“收集”进程想要写入磁盘的数据。但是,如果您明确地告诉操作系统编写小部分,那么它就会这样做。你正在这样做,这是缓慢的。请参阅我的编辑。@Jan PhilipGehrcke:有没有办法创建缓冲文件编写器?@Aarondigula:如果在调用Python的
open()
时未指定
buffering
参数,根据“系统默认值”,通常会应用一个(小)缓冲区。未记录此缓冲区的大小。对于某些版本的glibc,这里有人确定它为8kb:。对于某些应用程序,使用
buffering
参数增加缓冲区大小是有意义的。不可能有一般性的陈述,但基准测试有帮助。有时,首先明确地收集内存中的数据是有意义的,因为要同意这个答案中的观点。这里需要注意的一件重要事情是
缓冲
参数。对于较小的数据集(数百或数千项,总数据以KBs为单位),两种方式的性能都没有显著差异。在我的分析中,每次迭代调用write所花费的时间与单个write调用所花费的时间相同(计算到毫秒精度)。我将缓冲设置为-1(默认操作系统块大小)。不,这不是主要瓶颈。我同意他生成数据的方式不是最优的,但这不是这个程序的瓶颈。他的瓶颈是效率低下的I/O。原始运行时间(在我的机器上)是0m28.587s。我的版本采用0m2.266s。您还将进行哪些影响更大的更改?删除while循环,只调用一次
write()
。大部分时间已经花在不必要的随机生成上。如果我拿走了92%的原始运行时间,那怎么不是瓶颈呢?一旦你解决了这个问题,我相信你的建议会派上用场。好吧,让我们达成一致:他的数据生成效率非常低,他的I/O代码效率非常低。两者中哪一个是主要瓶颈取决于系统(在我的SSD供电系统上,CPU性能良好,这是I/O)。