我运行以下脚本从文件f中提取文件g中的域的IP地址。值得一提的是,它们是路径中的11个文件,每个文件大约有8亿行(每个文件f)。在这个脚本中我将文件g加载到内存中的字典d中然后我将文件f的行与字典d中的项目进行比较,如果有,我检查d中的bl_date是否在f之间的日期之间,然后把它写到另一个字典dns_dic。以下是我的脚本的样子:
path = '/data/data/2014*.M.mtbl.A.1'
def process_file(file):
start = time()
dns_dic=defaultdict(set)
d = defaultdict(set)
filename =file.split('/')[-1]
print(file)
g = open ('/data/data/ap2014-2dom.txt','r')
for line in g:
line = line.strip('\n')
domain, bl_date= line.split('|')
bl_date = int(bl_date)
if domain in d:
d[domain].add(bl_date)
else:
d[domain] = set([bl_date])
print("loaded APWG in %.fs" % (time()-start))
stat_d, stat_dt = 0, 0
f = open(file,'r')
with open ('/data/data/overlap_last_%s.txt' % filename,'a') as w:
for n, line in enumerate(f):
line=line.strip('')
try:
jdata = json.loads(line)
dom = jdata.get('bailiwick')[:-1]
except:
pass
if dom in d:
stat_d += 1
for bl_date in d.get(dom):
if jdata.get('time_first') <= bl_date <= jdata.get('time_last'):
stat_dt += 1
dns_dic[dom].update(jdata.get('rdata', []))
for domain,ips in dns_dic.items():
for ip in ips:
w.write('%s|%s\n' % (domain,ip))
w.flush()
if __name__ == "__main__":
files_list = glob(path)
cores = 11
print("Using %d cores" % cores)
pp = Pool(processes=cores)
pp.imap_unordered(process_file, files_list)
pp.close()
pp.join()
这是文件f:
{"bailiwick":"ou.ac.","time_last": 1493687431,"time_first": 1393687431,"rdata": ["50.21.180.100"]}
{"bailiwick": "ow.ac.","time_last": 1395267335,"time_first": 1395267335,"rdata": ["50.21.180.100"]}
{"bailiwick":"ox.ac.","time_last": 1399742959,"time_first": 1393639617,"rdata": ["65.254.35.122", "216.180.224.42"]}
这是文件g:
ou.ac|1407101455
ox.ac|1399553282
ox.ac|1300084462
ox.ac|1400243222
预期结果:
ou.ac|["50.21.180.100"]
ox.ac|["65.254.35.122", "216.180.224.42"]
有人可以帮我找出为什么在某些时候脚本变得非常慢,尽管内存使用时间总是大约400 MG。
答案 0 :(得分:0)
即使它没有改变整体计算复杂性,我也会从避免冗余的dict查找操作开始。例如,而不是
if domain in d:
d[domain].add(bl_date)
else:
d[domain] = set([bl_date])
你可能想做
d.setdefault(domain, set()).add(bl_date)
为了执行一次查找而不是两次。但实际上,set
似乎不是存储域访问时间戳的最佳选择。如果您使用了列表,则可以在开始将每个域的时间戳与f
的会话数据进行匹配之前对其进行排序。这样,您只需将每个会话的字段time_last
和time_first
与域时间戳列表中的第一个和最后一个元素进行比较,以确定是否要放置IP地址进入dns_dic[dom]
。
通常,您在for bl_date in d.get(dom):
循环中执行了大量不必要的工作。至少,在bl_date
和time_last
字段之间的第一个time_first
,您应该终止循环。根据{{1}}的长度,这可能是您的瓶颈。