Python:为什么这个脚本在一段时间后变得非常慢?

Python:为什么这个脚本在一段时间后变得非常慢?,python,performance,dictionary,Python,Performance,Dictionary,我正在运行下面的脚本从文件f中提取文件g中域的ip地址。值得一提的是,路径中有11个文件,每个文件都有大约8亿行。在这个脚本中,我将文件g加载到内存中的字典d中,然后将文件f的行与字典d中的项进行比较,如果有,我检查d中的bl_日期是否在f中的日期之间,然后将其写入另一个字典dns_dic。以下是我的脚本的外观: path = '/data/data/2014*.M.mtbl.A.1' def process_file(file): start = time() dns_dic

我正在运行下面的脚本从文件f中提取文件g中域的ip地址。值得一提的是,路径中有11个文件,每个文件都有大约8亿行。在这个脚本中,我将文件g加载到内存中的字典d中,然后将文件f的行与字典d中的项进行比较,如果有,我检查d中的bl_日期是否在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()
以下是文件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左右。

即使它不会改变总体计算复杂性,我还是从避免冗余的dict查找操作开始。例如,而不是

if domain in d:
    d[domain].add(bl_date)
else:
    d[domain] = set([bl_date])
你可能想这样做

d.setdefault(domain, set()).add(bl_date)
以便执行一次而不是两次查找。但实际上,似乎集合并不是存储域访问时间戳的完美选择。如果改用列表,则可以在开始将每个域的时间戳与f中的会话数据进行匹配之前对其进行排序。这样,您只需将每个会话的字段time_last和time_first与域的时间戳列表中的第一个和最后一个元素进行比较,以确定IP地址是否要放入dns_dic[dom]


通常,您在d.getdom:loop中的for bl_date中做了很多不必要的工作。至少,在位于time_last和time_first字段之间的第一个bl_日期,您应该终止循环。取决于g的长度,这可能是您的瓶颈。

是否有一个原因让您一次打开整个文件,而不是逐行打开?如果您指的是文件g,是的,因为我在字典d中加载了一次,然后比较文件f,逐行访问此字典d。哪一个是您的大文件?@user5061文件对象上的循环一次只返回一行。为什么每次写入后都要调用w.flush?这导致了大量多余的系统调用。您真的需要实时文件写入吗?我只是避免调用w.flush,只是确保文件w已正确关闭。re是瓶颈,计算上这是在On*maxd中,其中n是文件f中的输入记录数,maxd是每个域的最大条目数。因此,事实上,我同意这是一个潜在的瓶颈。除了CPU或内存资源耗尽的系统外,计算还包括许多字典查找,其复杂性为O log d,导致T=O n d log d=O n log d!,如果我没弄错的话。正如我所提议的,我们至少可以达到O logd。因此,尽管如此,整个IP提取仍将需要线性时间,但不会出现d=n和O n²的最坏情况。这似乎是正确的吗?dict查找是O1根据,但如果^2上的d=n=>是,注意:d是一个defaultdictset。换句话说,您可以只执行d[domain].addbl_date,这完全等同于d.setdefaultdomain,set.addbl_date但它更有效,因为它避免了创建大量空集。@J.Katzwinkel我在d.getdom中查找不同bl_date的原因是,我需要每个不同时间戳的ip地址,假设它可能会更改。这就是你的建议在这里行不通的原因
d.setdefault(domain, set()).add(bl_date)