需要很长时间才能运行的python脚本
我正在用python编写脚本来解析ldap日志,然后获取每个用户的搜索/绑定数量。我在样本文件和小文件上测试我的代码,直到5-10MB的大小运行得很快,并在我的本地PC上在1分钟内完成。但是,当我在一个价值18M的文件上运行该脚本时,其大约有150000行,大约需要5分钟,我希望在100M的文件大小上运行此脚本,并且可能在每次运行时都有5-6个文件,这意味着脚本具有在每次运行中解析几乎600-700M的数据。但是我想这需要很长时间才能运行,所以如果我的下面的代码可以在执行时间方面获得更好的性能,那么我需要一些建议。需要很长时间才能运行的python脚本
import os,re,datetime
from collections import defaultdict
d=defaultdict(list)
k=defaultdict(list)
start_time=datetime.datetime.now()
fh = open("C:\\Rohit\\ECD Utilization Script - Copy\\logdir\\access","r").read()
pat=re.compile(' BIND REQ .*conn=([\d]*).*dn=(.*")')
srchStr='\n'.join(re.findall(r' SEARCH REQ .*',fh))
bindlist=re.findall(pat,fh)
for entry in bindlist:
d[entry[-1].split(",")[0]].append(entry[0])
for key in d:
for con in d[key]:
count = re.findall(con,srchStr)
k[key].append((con,len(count)))
#
for key in k:
print("Number of searches by ",key, " : ",sum([i[1] for i in k[key]]))
for key in d:
print("No of bind ",key," = ",len(d[key]))
end_time=datetime.datetime.now()
print("Total time taken - {}".format(end_time-start_time))
我能用下面的代码解决我的问题。
import os,re,datetime
from collections import defaultdict
start_time=datetime.datetime.now()
bind_count=defaultdict(int)
search_conn=defaultdict(int)
bind_conn=defaultdict(str)
j=defaultdict(int)
fh = open("C:\\access","r")
total_searches=0
total_binds=0
for line in fh:
reg1=re.search(r' BIND REQ .*conn=(\d+).*dn=(.*")', line)
reg2=re.search(r' SEARCH REQ .*conn=(\d+).*', line)
if reg1:
total_binds+=1
uid,con=reg1.group(2,1)
bind_count[uid]=bind_count[uid]+1
bind_conn[con]=uid
if reg2:
total_searches+=1
skey=reg2.group(1)
search_conn[skey] = search_conn[skey]+1
for conid in search_conn:
if conid in bind_conn:
new_key=bind_conn[conid]
j[new_key]=j[new_key]+search_conn[conid]
for k,v in bind_count.items():
print(k," = ",v)
print("*"*80)
for k,v in j.items():
print(k,"-->",v)
fh.close()
del search_conn
del bind_conn
end_time=datetime.datetime.now()
print("Total time taken - {}".format(end_time-start_time))
使用itertools库而不是这么多的循环。
您的脚本具有二次复杂性:对于文件中的每一行,您将再次进行读取以匹配日志条目。 我的建议是只读一次文件并计算所需条目(匹配的一个(“BIND REQ”))的出现次数。
我已经在一定程度上编辑了我的代码,但是我仍然无法摆脱这个冗长的循环,这是问题的关键。你能否建议一个更好的方法来做到这一点。 '用于d键: 在d [键] CON: 计数= re.findall(CON,srchStr) K [键] .append((CON,LEN(计数)))' 该循环赢得” t对小文件来说是一个问题,但在大文件中,d [key]的值列表长度也可以达到34000,所以有很大的计算 – Rohit
你好,请你回答? – Rohit
我在这里。我认为它更容易(如果我理解你的代码)一次处理一行输入文件。在其上搜索你需要的字符串,并在数据结构中添加事件(就像保存计数的字典)。 – pinturic
你上线做对整个文件多次扫描
count = re.findall('SEARCH REQ.*'+conid,fh1)
避免这一点。这是你的主要问题。获取列表中的所有conid,并重新迭代文件并列出,而内部循环应由conid组成。将它从外部循环中移出。你会做两个文件扫描。
此外,由于它是普通的Python与PyPy运行更快的运行。
你可以用FSM和花更多的RAM来做到这一点。这是一个提示,你将不得不自己做你的FSM。
编辑1:这是我看到日志文件后编写的脚本版本。如果有任何错误,请纠正:
#!/usr/bin/env python
import sys
import re
def parse(filepath):
d = {}
regex1 = re.compile(r'(.*)?BIND\sREQ(.*)uid=(\w+)')
regex2 = re.compile(r'(.*)?SEARCH\sREQ(.*)uid=(\w+)')
with open(filepath, 'r') as f:
for l in f:
m = re.search(regex1, l)
if m:
# print (m.group(3))
uid = m.group(3)
if uid in d:
d[uid]['bind_count'] += 1
else:
d[uid] = {}
d[uid]['bind_count'] = 1
d[uid]['search_count'] = 0
m = re.search(regex2, l)
if m:
# print (m.group(3))
uid = m.group(3)
if uid in d:
d[uid]['search_count'] += 1
else:
d[uid] = {}
d[uid]['search_count'] = 1
d[uid]['bind_count'] = 0
for k in d:
print('user id = ' + k, 'Bind count = ' + str(d[k]['bind_count']), 'Search count = ' + str(d[k]['search_count']))
def process_args():
if sys.argv < 2:
print('Usage: parse_ldap_log.py log_filepath')
exit(1)
if __name__ == '__main__':
process_args()
parse(sys.argv[1])
感谢上帝,它并不足以保证FSM。
下面的代码如何做得更好......在下面的迭代中会有很多重复,我怎么能避免这种情况。 (con,srchStr) k [key] .append((con,len(count))) – Rohit
构造FSM。这是最好的方法。 – user902384
你能指导我在某个方向上,这样我就可以开始了。 – Rohit
你可以请分享一些见解如何做到这一点,我很新,并没有使用itertools到现在。任何开始将是很大的帮助。 – Rohit
我该如何使用itertools来避免下面的循环 '对于key in d:for con in d [key]:count = re.findall(con,fh1)k [key] .append((con,len(count) ))' – Rohit
你可以在上面的评论中回答我的问题吗? – Rohit