我有以下代码: 代码1:
logfile = open(logfile, 'r')
logdata = logfile.read()
logfile.close()
CurBeginA = BeginSearchDVar
CurEndinA = EndinSearchDVar
matchesBegin = re.search(str(BeginTimeFirstEpoch), logdata)
matchesEnd = re.search(str(EndinTimeFirstEpoch), logdata)
BeginSearchDVar = BeginTimeFirstEpoch
EndinSearchDVar = EndinTimeFirstEpoch
在脚本的另一部分中也有此代码:代码2
TheTimeStamps = [ x.split(' ')[0][1:-1] for x in open(logfile).readlines() ]
很明显,我在两次加载日志文件。我想避免这种情况。无论如何,我可以在代码2中执行我在代码1中所做的事情吗?这样,日志文件只加载一次?
在代码1中,我正在搜索日志以确保在不同的行中找到两个非常特定的模式。
在代码2中,我仅提取日志文件中所有行的第一列。
如何更好地对其进行优化?我正在当前大小为480MB的日志文件上运行此脚本,脚本将在大约12秒内完成。考虑到此日志可以达到1GB甚至2GB的大小,因此我想使其尽可能高效。
更新:
因此@abernert中的代码有效。我继续并为其添加了额外的逻辑,现在,它不再起作用。以下是我现在拥有的修改后的代码。我在这里基本上要做的是,如果在日志中找到matchsBegin和matchsEnd中的模式,那么,将日志从matchsBegin搜索到matchsEnd并仅打印出包含stringA和stringB的行:
matchesBegin, matchesEnd = None, None
beginStr, endStr = str(BeginTimeFirstEpoch).encode(), str(EndinTimeFirstEpoch).encode()
AllTimeStamps = []
mylist = []
with open(logfile, 'rb') as input_data:
def SearchFirst():
matchesBegin, matchesEnd = None, None
for line in input_data:
if not matchesBegin:
matchesBegin = beginStr in line
if not matchesEnd:
matchesEnd = endStr in line
return(matchesBegin, matchesEnd)
matchesBegin, matchesEndin = SearchFirst()
#print type(matchesBegin)
#print type(matchesEndin)
#if str(matchesBegin) == "True" and str(matchesEnd) == "True":
if matchesBegin is True and matchesEndin is True:
rangelines = 0
for line in input_data:
print line
if beginStr in line[0:25]: # Or whatever test is needed
rangelines += 1
#print line.strip()
if re.search(stringA, line) and re.search(stringB, line):
mylist.append((line.strip()))
break
for line in input_data: # This keeps reading the file
print line
if endStr in line[0:25]:
rangelines += 1
if re.search(stringA, line) and re.search(stringB, line):
mylist.append((line.strip()))
break
if re.search(stringA, line) and re.search(stringB, line):
rangelines += 1
mylist.append((line.strip()))
else:
rangelines += 1
#return(mylist,rangelines)
print(mylist,rangelines)
AllTimeStamps.append(line.split(' ')[0][1:-1])
以上代码中我做了什么错事?
答案 0 :(得分:1)
首先,几乎没有充分的理由致电readlines()
。文件已经是行的迭代,因此您可以循环遍历该文件。将所有这些行读入内存并建立一个庞大的列表只会浪费时间和内存。
另一方面,调用read()
有时会很有用。 确实必须将整个内容作为一个大字符串读取到内存中,但是与逐行搜索相比,对一个大字符串进行正则表达式搜索可以使事情加速得足够快,从而浪费了时间和空间远远超过了补偿。
但是,如果您希望将其减少到文件的单次传递,因为您已经必须逐行进行迭代,那么实际上除了行行regex搜索之外,别无选择。这应该有效(您尚未显示图案,但根据名称,我猜它们不应跨越线边界,也不是多线或点状图案),但是实际上是更快还是更慢取决于所有因素。
无论如何,如果有帮助,请参见当然值得尝试。 (而且,在我们讨论时,我将使用with
语句来确保关闭文件,而不是像在第二部分中那样泄漏它。)
CurBeginA = BeginSearchDVar
CurEndinA = EndinSearchDVar
BeginSearchDVar = BeginTimeFirstEpoch
EndinSearchDVar = EndinTimeFirstEpoch
matchesBegin, matchesEnd = None, None
TheTimeStamps = []
with open(logfile) as f:
for line in f:
if not matchesBegin:
matchesBegin = re.search(str(BeginTimeFirstEpoch), line)
if not matchesEnd:
matchesEnd = re.search(str(EndinTimeFirstEpoch), line)
TheTimeStamps.append(line.split(' ')[0][1:-1])
您可以在此处进行一些其他小的更改,可能会有所帮助。
我不知道BeginTimeFirstEpoch
是什么,但是您正在使用str(BeginTimeFirstEpoch)
的事实意味着它根本不是正则表达式模式,而是类似datetime
对象或int
?并且您实际上并不需要匹配对象,您只需要知道是否存在 匹配项?如果是这样,您可以删除regex
并进行简单的子字符串搜索,这会更快一些:
matchesBegin, matchesEnd = None, None
beginStr, endStr = str(BeginTimeFirstEpoch), str(EndinTimeFirstEpoch)
with …
# …
if not matchesBegin:
matchesBegin = beginStr in line
if not matchesEnd:
matchesEnd = endStr in line
如果您的搜索字符串和时间戳等全为纯ASCII,则以二进制模式处理文件可能会更快,只解码需要存储的位,而不是所有内容:
matchesBegin, matchesEnd = None, None
beginStr, endStr = str(BeginTimeFirstEpoch).encode(), str(EndinTimeFirstEpoch).encode()
with open(logFile, 'rb') as f:
# …
if not matchesBegin:
matchesBegin = beginStr in line
if not matchesEnd:
matchesEnd = endStr in line
TheTimeStamps.append(line.split(b' ')[0][1:-1].decode())
最后,我怀疑str.split
是否在您的代码瓶颈附近,但是,以防万一……当我们只希望第一次拆分时,为什么还要在所有空格上拆分呢?
TheTimeStamps.append(line.split(b' ', 1)[0][1:-1].decode())