【问题标题】:Performance improvement when reading txt file读取txt文件时的性能提升
【发布时间】:2015-07-22 13:04:41
【问题描述】:

我正在寻找我正在执行的任务的性能改进。

任务很简单:从 .txt 文件到 SQL 数据库。

所以 txt 文件包含一堆看起来像这样的行:

200101 35.922 2.127 1.182 1.182 1.418 1.654

解释:

200111: 是信息,包含在20 (channel num) 01 (page num) 11 (code)

其余的双精度值只是值:I1、I2...直到 I6

因此,SQL 文件将具有 [channel, page, code, I1, I2, I3, I4, I5, I6, passed] 列作为列

问题在于,在 txt 文件中,code 可以是 00、11、10、01 或 22,并且根据代码,我需要使用 I 的值执行一项或多项操作来决定通过=1 或通过=0。例如,在这种情况下,如果code=11passed=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

那么,有什么比使用ifclause 检查每一行更好或更省时的方法

【问题讨论】:

  • 你为什么不分析你的脚本并找出它慢的地方而不仅仅是猜测呢?几条if 语句所花费的时间将与磁盘IO 相形见绌。
  • 我会使用 csv 模块来解析你的文件
  • @Colonel,完成,瓶颈在代码的那部分
  • if 语句中检查?听起来很腥。您可以将函数存储在字典中并使用前两个字符作为键。
  • 您可能会发现 pandas 很有用

标签: python performance processing-efficiency


【解决方案1】:

只进行一次拆分,您可能会得到一些非常轻微的改进:

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

第二个建议(使用切片获取固定长度字段):

# 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。如果数据库和驱动程序允许,我唯一可以建议做的事情是多个 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

【讨论】:

  • 很好的答案!谢谢,我相信通过所有这些我可以得到一些改进。我当然将此标记为答案!
猜你喜欢
  • 1970-01-01
  • 2017-01-13
  • 2019-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
  • 2021-07-14
  • 2011-12-04
相关资源
最近更新 更多