我正在编写一个Python脚本来浏览两个文件 - 一个包含UUID列表,另一个包含大量日志条目 - 每行包含一个来自另一个文件的UUID。该程序的目的是从file1创建UUIDS列表,然后每次在日志文件中找到UUID时,每次找到匹配时都会增加相关值。
故事很长,请计算每个UUID在日志文件中出现的次数。 目前,我有一个列表,其中填充了UUID作为键,并且“点击”作为值。然后是另一个循环,它迭代日志文件的每一行,并检查日志中的UUID是否与UUID列表中的UUID匹配。如果匹配,则递增该值。
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的性能差异可以忽略不计。如果有人有任何其他方法,我将非常感激:)
答案 0 :(得分:14)
从功能上思考!
编写一个函数,它将获取日志文件的一行并返回uuid。称之为uuid
,比如说。
将此函数应用于日志文件的每一行。如果您使用的是Python 3,则可以使用内置函数映射;否则,你需要使用itertools.imap。
将此迭代器传递给collections.Counter。
collections.Counter(map(uuid, open("log.txt")))
这将非常有效。
一对评论:
这完全忽略了UUID列表,只计算出现在日志文件中的UUID。如果你不想要这个,你需要稍微修改一下程序。
答案 1 :(得分:4)
就像上面的人说的那样,使用10GB的文件你可能会很快达到磁盘的极限。对于仅代码改进,生成器建议很棒。在python 2.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
答案 2 :(得分:3)
你试过mincemeat.py吗?它是MapReduce分布式计算框架的Python实现。我不确定你是否会获得性能提升,因为我在使用它之前还没有处理过10GB的数据,尽管你可能会探索这个框架。
答案 3 :(得分:3)
这不是你问题的5行答案,但在PyCon'08上有一个名为Generator Tricks for System Programmers的优秀教程。还有一个名为A Curious Course on Coroutines and Concurrency的后续教程。
Generator教程专门以大日志文件处理为例。
答案 4 :(得分:0)
使用分析器http://docs.python.org/library/profile.html
尝试测量花费大部分时间的位置最佳优化将取决于数据的性质:如果uuids列表不是很长,您可能会发现,例如,大部分时间花在“if logFunc.progress”上( lineCount,logSize)“。如果列表 非常长,那么它可以帮助将uidHits.keys()
的结果保存到循环外的变量并迭代它而不是字典本身,但Rosh Oxymoron建议找到id首先然后在uidHits中检查它可能会有所帮助。
在任何情况下,您都可以删除lineCount
变量,然后使用i
。如果行很长,find(uid) != -1
可能会优于count(uid) == 1
。