如何提高python中这个readline循环的速度?

Bir*_*irt 2 python loops readline

我正在将文本格式的Databasedump的几个部分导入MySQL,问题是在有趣的数据之前,非常有趣的东西面前.我写了这个循环来获取所需的数据:

def readloop(DBFILE):
    txtdb=open(DBFILE, 'r')

sline = ""

# loop till 1st "customernum:" is found
while sline.startswith("customernum:  ") is False: 
    sline = txtdb.readline()

while sline.startswith("customernum:  "):
    data = []
    data.append(sline)
    sline = txtdb.readline()
    while sline.startswith("customernum:  ") is False:
        data.append(sline)
        sline = txtdb.readline()
        if len(sline) == 0:
            break
    customernum = getitem(data, "customernum:  ")
    street = getitem(data, "street:  ")
    country = getitem(data, "country:  ")
    zip = getitem(data, "zip:  ")
Run Code Online (Sandbox Code Playgroud)

Textfile非常庞大,所以只需循环直到第一个想要的条目需要花费很多时间.任何人都有一个想法,如果这可以更快地完成(或者如果整个方式我修复这不是最好的主意)?

提前谢谢了!

Pau*_*McG 5

请不要写这段代码:

while condition is False:
Run Code Online (Sandbox Code Playgroud)

布尔条件是大声喊叫的布尔值,因此可以直接测试(或否定和测试)它们:

while not condition:
Run Code Online (Sandbox Code Playgroud)

你的第二个while循环不是写成"条件为真:",我很好奇你为什么觉得需要在第一个中测试"是假的".

拉出dis模块,我想我会进一步剖析这个.在我的pyparsing体验中,函数调用是总性能杀手,因此如果可能的话避免函数调用会很好.这是你原来的测试:

>>> test = lambda t : t.startswith('customernum') is False
>>> dis.dis(test)
  1           0 LOAD_FAST                0 (t)
              3 LOAD_ATTR                0 (startswith)
              6 LOAD_CONST               0 ('customernum')
              9 CALL_FUNCTION            1
             12 LOAD_GLOBAL              1 (False)
             15 COMPARE_OP               8 (is)
             18 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

两个昂贵的东西在这里发生,CALL_FUNCTIONLOAD_GLOBAL.您可以LOAD_GLOBAL通过为False定义本地名称来减少:

>>> test = lambda t,False=False : t.startswith('customernum') is False
>>> dis.dis(test)
  1           0 LOAD_FAST                0 (t)
              3 LOAD_ATTR                0 (startswith)
              6 LOAD_CONST               0 ('customernum')
              9 CALL_FUNCTION            1
             12 LOAD_FAST                1 (False)
             15 COMPARE_OP               8 (is)
             18 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

但是,如果我们完全放弃'是'测试怎么办?:

>>> test = lambda t : not t.startswith('customernum')
>>> dis.dis(test)
  1           0 LOAD_FAST                0 (t)
              3 LOAD_ATTR                0 (startswith)
              6 LOAD_CONST               0 ('customernum')
              9 CALL_FUNCTION            1
             12 UNARY_NOT
             13 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

我们已经崩溃了LOAD_xxx,COMPARE_OP并且很简单UNARY_NOT."是假的"肯定是没有帮助性能导致任何.

现在如果我们可以完全消除一条线而不进行任何函数调用.如果该行的第一个字符不是'c',则它无法以startwith('customernum')开头.我们试试看:

>>> test = lambda t : t[0] != 'c' and not t.startswith('customernum')
>>> dis.dis(test)
  1           0 LOAD_FAST                0 (t)
              3 LOAD_CONST               0 (0)
              6 BINARY_SUBSCR
              7 LOAD_CONST               1 ('c')
             10 COMPARE_OP               3 (!=)
             13 JUMP_IF_FALSE           14 (to 30)
             16 POP_TOP
             17 LOAD_FAST                0 (t)
             20 LOAD_ATTR                0 (startswith)
             23 LOAD_CONST               2 ('customernum')
             26 CALL_FUNCTION            1
             29 UNARY_NOT
        >>   30 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

(请注意,使用[0]得到一个字符串的第一个字符并没有创建一个切片-其实这是非常快)

现在,假设没有大量以'c'开头的行,粗剪滤波器可以使用所有相当快的指令消除一条线.实际上,通过测试"t [0]!='c'"而不是"not t [0] =='c'",我们为自己保存了一条无关的UNARY_NOT指令.

所以使用这个关于捷径优化的学习,我建议改变这段代码:

while sline.startswith("customernum:  ") is False:
    sline = txtdb.readline()

while sline.startswith("customernum:  "):
    ... do the rest of the customer data stuff...
Run Code Online (Sandbox Code Playgroud)

对此:

for sline in txtdb:
    if sline[0] == 'c' and \ 
       sline.startswith("customernum:  "):
        ... do the rest of the customer data stuff...
Run Code Online (Sandbox Code Playgroud)

请注意,我还删除了.readline()函数调用,并使用"for tline in txtdb"迭代文件.

我意识到Alex完全提供了不同的代码体,用于找到第一个"customernum"行,但我会尝试在算法的一般范围内进行优化,然后再拔出大而模糊的块读取枪.