读取 txt 文件时的性能改进
Performance improvement when reading txt file
我正在寻找我正在做的任务的性能改进。
任务非常简单:从 .txt 文件到 SQL 数据库。
所以 txt 文件由一堆看起来像这样的行组成:
200101 35.922 2.127 1.182 1.182 1.418 1.654
解释:
200111
:是信息,包括20
(频道数) 01
(页数) 11
(代码)
其余双精度值只是值:I1、I2...直到 I6
因此,SQL 文件将包含 [channel, page, code, I1, I2, I3, I4, I5, I6, passed]
列
问题是,在 txt 文件中,code
可以是 00、11、10、01 或 22,并且根据代码,我需要使用这些值执行一个或另一个操作我决定 passed=1 或 passed=0。例如,在这种情况下,如果 code=11
、passed=1 if I1>I3 and I6<1
txt 中的行按代码排序。
所以,有了这个解释,我基本上就是这样做的:
with open(txtFile, 'r') as txt:
for line in txt:
currentLine = line.split(' ')[0]
if currentLine.endswith('00'):
#do some actions here
if currentLine.endswith('01'):
#do some actions here
#...
#and so on
# and of course write to SQL file
那么,有没有比用 if
子句检查每一行更好或更省时的方法
你可能只做一次拆分就会得到一些非常轻微的改进:
currentLine = line.split(' ', 1)[0]
或者如果您感兴趣的第一个字段始终具有相同的长度(使用您的示例为 6),您可以尝试仅获取这些字符:
currentLine = line[:6]
如果第一个字段的长度是可变的,你可以试试这个:
currentLine = line[:line.index(' ')]
这里有一些计时,看看哪个更快...
您当前的方法:
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "lineCode = l.split(' ')[0]"
1000000 loops, best of 3: 0.61 usec per loop
第一个建议(限制拆分一次):
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "lineCode = l.split(' ', 1)[0]"
1000000 loops, best of 3: 0.237 usec per loop
第二个建议(使用slice获取定长字段):
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l[:6]"
10000000 loops, best of 3: 0.0708 usec per loop
第三条建议(使用切片+索引获取变长字段):
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l[:l.index(' ')]"
1000000 loops, best of 3: 0.208 usec per loop
在我的初步测试中,如果你能做到,建议 2 似乎是最快的。其他两个建议在性能上非常相似,但比您当前的方法好很多。
显然,这些时间会根据您所使用的平台而有所不同 运行 但相对而言,性能改进应该在任何地方都有效。
现在,综上所述,我同意您的其他评论员的观点,即您的缓慢可能来自其他地方。如果我不得不猜测那将是您的 SQL INSERT。我唯一可以建议做的是,如果数据库和驱动程序允许,或者将您的 SQL 语句写入格式正确的文件并让另一个工具进行批量导入(甚至可以使用 Python 子进程模块)。
其他想法
如果您只需要测试这两个字符(第 5 个和第 6 个),那么这是我发现的最有效的方法。它消除了您正在使用的低效 split
和较慢的 endswith
.
你的:
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l.split(' ')[0]; currentLine.endswith('00')"
1000000 loops, best of 3: 0.72 usec per loop
更好:
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l[:6]; lineCode = currentLine[4:]; lineCode == '00'"
10000000 loops, best of 3: 0.161 usec per loop
最佳:
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l[4:6]; currentLine == '00'"
10000000 loops, best of 3: 0.102 usec per loop
所以,你可以这样做:
with open(txtFile, 'r') as txt:
for line in txt:
currentLine = line[4:6]
if currentLine == '00':
#do some actions here
elif currentLine == '01':
#do some actions here
#...
#and so on
# and of course write to SQL file
我正在寻找我正在做的任务的性能改进。
任务非常简单:从 .txt 文件到 SQL 数据库。
所以 txt 文件由一堆看起来像这样的行组成:
200101 35.922 2.127 1.182 1.182 1.418 1.654
解释:
200111
:是信息,包括20
(频道数) 01
(页数) 11
(代码)
其余双精度值只是值:I1、I2...直到 I6
因此,SQL 文件将包含 [channel, page, code, I1, I2, I3, I4, I5, I6, passed]
问题是,在 txt 文件中,code
可以是 00、11、10、01 或 22,并且根据代码,我需要使用这些值执行一个或另一个操作我决定 passed=1 或 passed=0。例如,在这种情况下,如果 code=11
、passed=1 if I1>I3 and I6<1
txt 中的行按代码排序。
所以,有了这个解释,我基本上就是这样做的:
with open(txtFile, 'r') as txt:
for line in txt:
currentLine = line.split(' ')[0]
if currentLine.endswith('00'):
#do some actions here
if currentLine.endswith('01'):
#do some actions here
#...
#and so on
# and of course write to SQL file
那么,有没有比用 if
子句检查每一行更好或更省时的方法
你可能只做一次拆分就会得到一些非常轻微的改进:
currentLine = line.split(' ', 1)[0]
或者如果您感兴趣的第一个字段始终具有相同的长度(使用您的示例为 6),您可以尝试仅获取这些字符:
currentLine = line[:6]
如果第一个字段的长度是可变的,你可以试试这个:
currentLine = line[:line.index(' ')]
这里有一些计时,看看哪个更快...
您当前的方法:
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "lineCode = l.split(' ')[0]"
1000000 loops, best of 3: 0.61 usec per loop
第一个建议(限制拆分一次):
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "lineCode = l.split(' ', 1)[0]"
1000000 loops, best of 3: 0.237 usec per loop
第二个建议(使用slice获取定长字段):
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l[:6]"
10000000 loops, best of 3: 0.0708 usec per loop
第三条建议(使用切片+索引获取变长字段):
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l[:l.index(' ')]"
1000000 loops, best of 3: 0.208 usec per loop
在我的初步测试中,如果你能做到,建议 2 似乎是最快的。其他两个建议在性能上非常相似,但比您当前的方法好很多。
显然,这些时间会根据您所使用的平台而有所不同 运行 但相对而言,性能改进应该在任何地方都有效。
现在,综上所述,我同意您的其他评论员的观点,即您的缓慢可能来自其他地方。如果我不得不猜测那将是您的 SQL INSERT。我唯一可以建议做的是,如果数据库和驱动程序允许,或者将您的 SQL 语句写入格式正确的文件并让另一个工具进行批量导入(甚至可以使用 Python 子进程模块)。
其他想法
如果您只需要测试这两个字符(第 5 个和第 6 个),那么这是我发现的最有效的方法。它消除了您正在使用的低效 split
和较慢的 endswith
.
你的:
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l.split(' ')[0]; currentLine.endswith('00')"
1000000 loops, best of 3: 0.72 usec per loop
更好:
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l[:6]; lineCode = currentLine[4:]; lineCode == '00'"
10000000 loops, best of 3: 0.161 usec per loop
最佳:
# python3 -m timeit -s "l = '200101 35.922 2.127 1.182 1.182 1.418 1.654'" "currentLine = l[4:6]; currentLine == '00'"
10000000 loops, best of 3: 0.102 usec per loop
所以,你可以这样做:
with open(txtFile, 'r') as txt:
for line in txt:
currentLine = line[4:6]
if currentLine == '00':
#do some actions here
elif currentLine == '01':
#do some actions here
#...
#and so on
# and of course write to SQL file