【发布时间】:2017-07-04 04:39:27
【问题描述】:
我有以下两难境地。我正在解析巨大的 CSV 文件,理论上可以包含无效记录,python。为了能够快速解决问题,我想查看错误消息中的行号。但是,由于我正在解析许多文件并且错误非常罕见,我不希望我的错误处理增加了主管道的开销。这就是为什么我不想使用enumerate 或类似方法的原因。
简而言之,我正在寻找一个像这样工作的get_line_number 函数:
with open('file.csv', 'r') as f:
for line in f:
try:
process(line)
except:
line_no = get_line_number(f)
raise RuntimeError('Error while processing the line ' + line_no)
但是,这似乎很复杂,因为 f.tell() will not work 在这个循环中。
编辑:
似乎开销相当大。在我的真实案例中(这很痛苦,因为文件是非常短的记录列表:单个浮点数、int-float 对或 string-int 对;file.csv 大约有 800MB 大,大约有 80M 行),它是enumerate 的每个文件读取大约需要 2.5 秒。出于某种原因,fileinput 非常很慢。
import timeit
s = """
with open('file.csv', 'r') as f:
for line in f:
pass
"""
print(timeit.repeat(s, number = 10, repeat = 3))
s = """
with open('file.csv', 'r') as f:
for idx, line in enumerate(f):
pass
"""
print(timeit.repeat(s, number = 10, repeat = 3))
s = """
count = 0
with open('file.csv', 'r') as f:
for line in f:
count += 1
"""
print(timeit.repeat(s, number = 10, repeat = 3))
setup = """
import fileinput
"""
s = """
for line in fileinput.input('file.csv'):
pass
"""
print(timeit.repeat(s, setup = setup, number = 10, repeat = 3))
输出
[45.790788270998746, 44.88589363079518, 44.93949336092919]
[70.25306860171258, 70.28569177398458, 70.2074502906762]
[75.43606997421011, 74.39759518811479, 75.02027251804247]
[325.1898657102138, 321.0400970801711, 326.23809849238023]
编辑 2:
接近真实世界的场景。 try-except 子句位于循环之外以减少开销。
import timeit
setup = """
def process(line):
if float(line) < 0.5:
outliers += 1
"""
s = """
outliers = 0
with open('file.csv', 'r') as f:
for line in f:
process(line)
"""
print(timeit.repeat(s, setup = setup, number = 10, repeat = 3))
s = """
outliers = 0
with open('file.csv', 'r') as f:
try:
for idx, line in enumerate(f):
process(line)
except ValueError:
raise RuntimeError('Invalid value in line' + (idx + 1)) from None
"""
print(timeit.repeat(s, setup = setup, number = 10, repeat = 3))
输出
[244.9097429071553, 242.84596176538616, 242.74369075801224
[293.32093235617504, 274.17732743313536, 274.00854821596295]
因此,就我而言,enumerate 的开销约为 10%。
【问题讨论】:
-
所以,我不得不问,问题是您的示例运行速度太慢还是您认为它可能运行速度太慢?它实际上对性能有多大影响?您是否测量了您知道没有错误的文件的差异?
-
哇,没想到会慢 2 倍。将您的
process(line)调用包含在try/catch中会有多大影响? -
我也不会,但是用
pass代替真正对数据做的任何事情并不是最公平的比较。此外,一个 csv 文件每行只有 10 个字节是非常不寻常的。 -
@nigel222:你的平台是什么?
-
您可以在
try/except内运行整个循环,从而减少开销。
标签: python performance io