gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-28 20:54:29 26 4
gpt4 key购买 nike

我正在将文本格式的 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: ")

文本文件非常大,所以循环直到第一个需要的条目需要很长时间。任何人都知道这是否可以更快地完成(或者如果我修复这的整个方法不是最好的主意)?

非常感谢!

最佳答案

请不要写这段代码:

while condition is False:

bool 条件是 bool 值,用于大声呼喊,因此可以直接测试(或否定和测试):

while not condition:

你的第二个 while 循环没有写成“while condition is True:”,我很好奇你为什么觉得需要在第一个循环中测试“is False”。

取出 dis 模块,我想我会进一步剖析它。在我的 pyparsing 经验中,函数调用是完全的性能 killer ,所以如果可能的话最好避免函数调用。这是您的原始测试:

>>> 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

这里发生了两件昂贵的事情,CALL_FUNCTIONLOAD_GLOBAL。您可以通过为 False 定义本地名称来减少 LOAD_GLOBAL:

>>> 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

但是如果我们完全放弃“is”测试呢?:

>>> 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

我们用一个简单的 UNARY_NOT 折叠了一个 LOAD_xxxCOMPARE_OP。 “is False”当然对性能没有任何帮助。

现在如果我们可以在根本不进行任何函数调用的情况下粗略地删除一行会怎样。如果该行的第一个字符不是'c',它就不可能以('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

(请注意,使用 [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...

对此:

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

请注意,我还删除了 .readline() 函数调用,并仅使用“for sline in txtdb”遍历文件。

我意识到 Alex 提供了完全不同的代码主体来查找第一个“customernum”行,但我会尝试在您的算法的一般范围内进行优化,然后再拿出大而晦涩的 block 读取枪。

关于python - 如何提高 python 中这个 readline 循环的速度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1415369/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com