Python中迭代大文件的最有效方法(10GB+;)
我正在编写一个Python脚本来遍历两个文件——一个包含UUID列表,另一个包含大量日志条目——每行包含另一个文件中的一个UUID。该程序的目的是从文件1创建一个UUID列表,然后每次在日志文件中找到UUID时,在每次找到匹配项时增加相关值 长话短说,计算每个UUID在日志文件中出现的次数。 目前,我有一个列表,其中UUID作为键填充,“hits”作为值填充。然后是另一个循环,循环遍历日志文件的每一行,并检查日志中的UUID是否与UUID列表中的UUID匹配。如果匹配,则递增该值Python中迭代大文件的最有效方法(10GB+;),python,file,design-patterns,matching,Python,File,Design Patterns,Matching,我正在编写一个Python脚本来遍历两个文件——一个包含UUID列表,另一个包含大量日志条目——每行包含另一个文件中的一个UUID。该程序的目的是从文件1创建一个UUID列表,然后每次在日志文件中找到UUID时,在每次找到匹配项时增加相关值 长话短说,计算每个UUID在日志文件中出现的次数。 目前,我有一个列表,其中UUID作为键填充,“hits”作为值填充。然后是另一个循环,循环遍历日志文件的每一行,并检查日志中的UUID是否与UUID列表中的UUID匹配。如果匹配,则递增该值 for
for i, logLine in enumerate(logHandle): #start matching UUID entries in log file to UUID from rulebase
if logFunc.progress(lineCount, logSize): #check progress
print logFunc.progress(lineCount, logSize) #print progress in 10% intervals
for uid in uidHits:
if logLine.count(uid) == 1: #for each UUID, check the current line of the log for a match in the UUID list
uidHits[uid] += 1 #if matched, increment the relevant value in the uidHits list
break #as we've already found the match, don't process the rest
lineCount += 1
它可以正常工作,但我相信有一种更有效的方法来处理文件。我阅读了一些指南,发现使用“count”比使用编译的正则表达式要快。我认为分块而不是逐行读取文件可以减少磁盘I/O时间,从而提高性能,但测试文件~200MB的性能差异是可以忽略的。如果有人有其他方法,我将非常感激:)从功能上思考
collections.Counter(map(uuid, open("log.txt")))
- 这将完全忽略UUID列表,只计算日志文件中出现的UUID。如果您不想这样做,您需要对程序进行一些修改
- 因为使用了错误的数据结构,所以代码速度很慢。你在这里想要的就是口述
- 你试过了吗?它是分布式计算框架的Python实现。我不确定您是否会获得性能提升,因为在使用10GB数据之前,我还没有处理过它,尽管您可能会探索这个框架。这不是对您的问题的5行回答,但PyCon'08提供了一个名为。还有一个后续教程叫做
生成器教程特别以大日志文件处理为例。正如上面的人所说,使用10GB文件,您可能会很快达到磁盘的极限。对于纯代码的改进,生成器建议非常有用。在Python2.x中,它看起来像
uuid_generator = (line.split(SPLIT_CHAR)[UUID_FIELD] for line in file)
听起来这实际上不一定是python的问题。如果您没有做任何比计算uuid更复杂的事情,那么Unix可能比python更快地解决您的问题
cut -d${SPLIT_CHAR} -f${UUID_FIELD} log_file.txt | sort | uniq -c
尝试使用探查器测量大部分时间花在哪里 优化的最佳位置取决于数据的性质:例如,如果UUID列表不是很长,您可能会发现很大一部分时间花在“If logFunc.progress(lineCount,logSize)”上。如果列表很长,则可以将
uidHits.keys()
的结果保存到循环外的变量中,并迭代该变量,而不是字典本身,但是Rosh Oxymoron建议首先查找id,然后在uidHits中检查它,这可能会更有用
在任何情况下,都可以消除
lineCount
变量,改用i
。和find(uid)!=-如果行很长,1
可能比count(uid)==1要好。文件I/O通常被缓冲,而不管您实际读取的块大小。是否需要更高效?需要多长时间?你需要多长时间?您可能已经达到了存储(磁盘)的性能极限,在这种情况下,无论Python脚本的速度有多快都无关紧要。它现在正在运行一个测试文件—它正在运行10GB文件的一半,大约需要30分钟。作为我第一次出游Python,我真的不知道这是快还是慢。无需在x分钟内完成,但更快更好;)在您的示例中,第二条if语句为空(之后没有缩进代码)。你能修好吗?你要检查文件中每一行的所有UID。相反,在每一行中找到UUID并在字典中查找。在代码中最常被调用的部分尽量少做。感谢您的输入-一旦这个测试运行完成,我得到了我的资源,我会看一看。我想我在dict上使用了一个列表,因为我想维护uuid的顺序,但我想我以后可以使用该列表作为索引,然后从dict中提取相应的值?@SG84您可能会看到一篇关于Python生成器的优秀文章,特别是关于处理大文件的文章。你会得到启发:-)我之前确实试过一个发电机,在我把大脑从地板上拿起来并让它工作后,性能提升与在文件上使用for循环没有太大区别。不过,感谢链接,这一切都有助于更好地阅读,因此在了解生成器和集合模块的诀窍之后,我修改了代码中的两个函数,250MB文件的总执行时间从96.4秒减少到5.4秒!!这是一场巨大的胜利。非常感谢大家的投入:)