2013-09-02 1 views
2

memory_profiler 패키지 (pip에서 다운로드)를 사용하여 놀고 있었는데, 특히 "반복기 목록"을 반복하면서 임시 목록을 먼저 작성하여 목록을 반복하는 메모리 효율성을 살펴 보았습니다.for 루프에서 메모리를 차지하는 것은 무엇입니까?

이것은 잠시 동안 만난 문제 였고 해결책을 벤치마킹하고 싶었습니다. 문제는 모든 요소가 "다루어 질 때까지"목록의 각 요소를 같은 목록의 다음 요소와 비교해야한다는 것이 었습니다. 그래서 이것은 O (n^2) 솔루션이 될 것이라고 생각합니다. (가장 순진한 솔루션을 선택한 경우 목록의 각 요소에 대해 목록을 반복합니다).

어쨌든 아래의 세 가지 기능은 모두 같은 일을합니다 (다소간). 자체적으로 압축 된 목록 (오프셋 단위)을 반복합니다.

import cProfile 

@profile 
def zips(): 
    li = range(1,20000000) 
    for tup in zip(li,li[1:]): 
     pass 
    del li 

@profile 
def izips(): 
    from itertools import izip 
    li = range(1,20000000) 
    for tup in izip(li,li[1:]): 
     pass 
    del li 

@profile 
def izips2(): 
    from itertools import izip 
    li = range(1,20000000) 
    for tup in izip(li,li[1:]): 
     del tup 
    del li 



if __name__ == '__main__': 
    zips() 
    # izips() 
    # izips2() 

(나에게) 놀라운 부분은 처음에는() 함수를 참아을 실행하고 내가 정리 않았다 생각하지만, 난 여전히 메모리에 ~ 1.5 GB로 결국, 메모리 사용량에 있었다 :

그런 다음
ipython -m memory_profiler python_profiling.py 
Filename: python_profiling.py 

Line # Mem usage Increment Line Contents 
================================================ 
    10        @profile 
    11 27.730 MB  0.000 MB def zips(): 
    12 649.301 MB 621.570 MB li = range(1,20000000) 
    13 3257.605 MB 2608.305 MB for tup in zip(li,li[1:]): 
    14 1702.504 MB -1555.102 MB  pass 
    15 1549.914 MB -152.590 MB del li 

나는 인터프리터 인스턴스를 종료하고() 함수 izips입니다 다음 테스트를 실행하는 그것을 다시 : 다음

ipython -m memory_profiler python_profiling.py 
Filename: python_profiling.py 

Line # Mem usage Increment Line Contents 
================================================ 
    17        @profile 
    18 27.449 MB  0.000 MB def izips(): 
    19 27.449 MB  0.000 MB from itertools import izip 
    20 649.051 MB 621.602 MB li = range(1,20000000) 
    21 1899.512 MB 1250.461 MB for tup in izip(li,li[1:]): 
    22 1746.922 MB -152.590 MB  pass 
    23 1594.332 MB -152.590 MB del li 

그리고 마지막으로 나는 인터프리터를 다시 시작한 후 다시 테스트를 (실행 비)) for 루프에서 튜플을 명시 적으로 삭제하려고 시도하여 메모리가 해제되었는지 확인하려고했습니다 (어쩌면 올바르게 생각하지 않을 수도 있습니다). 그것이 차이를 만들지 않았 음을 알았 기 때문에 GC를 묻지 않거나 메모리 오버 헤드의 원인이 아님을 짐작할 수 있습니다.

ipython -m memory_profiler python_profiling.py 
Filename: python_profiling.py 

Line # Mem usage Increment Line Contents 
================================================ 
    25        @profile 
    26 20.109 MB  0.000 MB def izips2(): 
    27 20.109 MB  0.000 MB from itertools import izip 
    28 641.676 MB 621.566 MB li = range(1,20000000) 
    29 1816.953 MB 1175.277 MB for tup in izip(li,li[1:]): 
    30 1664.387 MB -152.566 MB  del tup 
    31 1511.797 MB -152.590 MB del li 

는 결론 : 나는 ~ 620.000 MB (메모리가이 목록을 저장하는 데 걸리는) 그러나보다 조금 더 기다리고 있었다 따라서 for 루프의 오버 헤드가 자체 최소한의 것을 생각하고, 대신 나는 ~ 20000.000의 메모리 목록과 ~보다 많은 오버 헤드를 가지고있는 것처럼 보입니다. 아무도 내가이 모든 메모리가 사용되는 것을 설명 할 수있게 도와 줄 수 있니? (그리고 각 실행이 끝날 때 ~ 1.5GB를 차지하는 것이 무엇입니까?)

답변

2

OS는 청크로 메모리를 할당하고 반드시 한 번에 모두 회수하지는 않습니다. 메모리 프로파일 링 패키지가 심각하게 부정확하다는 사실을 발견했습니다. 쉽게 목록에 필요한 메모리 공간을 두 배로, 1 개 요소, 거의 완전히 새로운 사본 -

귀하의 li[1:] 슬라이스 (2 * 10 ** 7)와 새로운 목록을 만듭니다. 또한 zip() 호출은 완전히 새로운 목록 객체 인 zipping 작업의 결과를 반환하며 중간 결과에 대한 메모리와 2 천만 개의 2 요소 튜플을 다시 필요로합니다.

당신은 자르는 대신 새로운 반복자를 사용할 수 있습니다리스트 반복자가 iter() 호출에서 반환

def zips(): 
    from itertools import izip 
    li = range(1,20000000) 
    next_li = iter(li) 
    next(next_li) # advance one step 
    for tup in izip(li, next_li): 
     pass 
    del li 

는 경량 훨씬 더; 원래 목록과 포인터에 대한 참조 만 유지합니다. izip()과 함께 사용하면 출력 목록을 만들지 않아도됩니다.

+0

'다음 (next_li)'을 원하셨습니까? – user2357112

+0

@ user2357112 : 예, 감사했습니다. –

관련 문제