2015-02-04 1 views
0

아래의 스크립트를 실행하여 파일 g의 도메인에 대해 파일 f에서 IP 주소를 추출합니다. 이 파일은 경로의 11 개 파일이고 각 파일에는 약 8 억 개의 행 (각 파일 f)이 있음을 언급 할 필요가 있습니다. 이 스크립트에서 나는 메모리에있는 사전 d에 파일 g를로드 할 때 d의 항목과 비교하여 파일 f의 행을 비교합니다. d의 bl_date가 f의 날짜 사이에 있는지 확인합니다. 그것을 다른 사전 dns_dic에 씁니다. 여기 Python : 왜이 ​​스크립트는 어느 시점 이후에 매우 느려지 는가?

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

파일 g를 원한다면 예 (d)를 한 번로드 한 다음 파일 f를이 사전에 줄 단위로 비교합니다. d. – UserYmY

+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_lasttime_first을 도메인 타임 스탬프 목록의 첫 번째 요소와 마지막 요소와 비교하여 IP 주소가 dns_dic[dom]에 들어가는 지 여부를 결정할 수 있습니다.

일반적으로 for bl_date in d.get(dom): 루프에서 많은 불필요한 작업을 수행하고 있습니다. 최소한 과 time_first 필드 사이에있는 첫 번째 bl_date에서 루프를 종료해야합니다. g의 길이에 따라 병목 현상이있을 수 있습니다.

+2

병목 현상을 계산하기 위해 이것은 O (n * max (d))에 있으며, 여기서 n은 파일 f의 입력 레코드 수이고 max (d)는 도메인 당 최대 항목 수입니다. 사실, 이것이 잠재적 병목 현상이라는 데 동의합니다. 일반적으로 CPU 나 메모리 자원이 부족한 시스템 외. – miraculixx

+1

계산에는 또한 실수가없는 경우 _O_ (log d)의 복잡도를 갖는 여러 사전 검색이 포함되어 _T_ = _O_ (n d log d) = _O_ (n log d!)가됩니다. 내가 제안한 것처럼 적어도 _O_ (n log d)에 도달 할 수 있습니다. 그럼에도 불구하고 전체 IP 추출은 그럼에도 불구하고 선형 시간을 취할 것입니다. 그러나 _O_ (n²)에서 d = n의 최악의 경우는 없습니다. 맞나요? –

+2

dict 조회는 https://wiki.python.org/moin/TimeComplexity에 따라 O (1)이지만 d = n => O (n^2) 인 경우 예 – miraculixx

관련 문제