(고성능 파이썬)
이 장에서 다루는 것
- 코드의 속도(CPU 속도)상 병목과 RAM 사용 병목을 파악하는 방법
- CPU와 메모리 사용량을 프로파일링 하는 방법
- 장기간 실행되는 앱의 프로파일링
- Cpython의 내부 동작
"감에 의존해서 코드 구조를 변경하기 전에 가설을 세우고 프로파일링을 해보는게 훨씬 합리적이다"
-> 프로파일링을 통해 해결해야할 병목 지점을 빠르게 찾아낼 수 있음
프로파일링
- 첫 번째 목표; 시스템의 어느 부분이 느린지, 어디서 RAM을 많이 쓰는지, 디스크 및 네트워크 I/O를 과도하게 발생시키는 부분이 어딘지 확인하는 것
- 코드를 작성할 때 모듈별로 미리 나누는 것이 프로파일링 할 때 편함 (프로파일링 시 10~100배 까지 느려짐)
기본적인 프로파일링 기법
- time.time() 와 timing decorator 를 활용한 시간 측정
- cProfile ; 어떤 함수가 가장 오래걸리는지 확인
- line_profiler ;선택한 함수를 한 줄씩 프로파일링할 수 있는 도구 (각 줄이 몇번 실행, 소요된 총 시간 검사)
- pref stat ; CPU에서 실행된 명령의 수와 CPU 캐시가 얼마나 효율적으로 활용 되었는지 알아 볼 수 있음
- heapy ; 파이썬 메모리에 상주하는 모든 객체를 살펴 볼 수 있음 (도무지 알 수 없는 메모리 누수 찾기)
- dowser ; 장시간 실행되는 시스템을 위한 도구
- memory_profiler ; RAM 사용량이 왜 높은지 찾는 도구 , 시간에 따른 RAM 사용 추이
* 어떤 방식으로 프로파일링 하든, 단위테스트를 제대로 작성해 둬야함
이책에선 프로파일링 기법을 소개하면서
쥘리아 집합이라는 것을 이용한다
CPU를 많이 사용하는 흥미로운 주제
복소수 c가 주어지고 그에 따른 쥘리아 집합 그래프를 계산하는 것 같다.
집합의 각 픽셀은 독립적으로 계산되기에 병렬 계산 또한 가능하다.
각 픽셀을 계산하는 데 몇 번이나 반복되는지 가늠하기 어려운 루프를 사용.
매 반복 마다 이 좌표가 무한 루프에 빠지는지 아닌지 검사함.
반복 횟수가 적을 수록 어두운 색 / 반복 거듭될 수록 밝은 색
f(z) = z^2 + c (z는 복소수)
- z의 절댓값이 2보다 작다면 이 함수 계속 반복
- 2 이상이면 루프를 빠져나가고 반복 수행 횟수 기록
- 무한 루프에 빠질 경우 maxiter만큼만 반복 후 빠져나옴
- z의 결과 값은 좌표로 활용 (복소 평면)
쥘리아 집합을 계산하는 코드 (바로가기)
어쨋든 실행 하면 time.time()을 이용해서
계산하는데 얼마나 걸리는지 출력됨
이미지 또한 아웃풋으로 나오는데, 색깔로써 어느 부분이 결정되는데에 오래걸리는지 알 수 있음
뭔가 모양이 나오기 때문에 신기함.
* 디버깅할 때와 마찬가지로 프로파일링에서도 print문은 가장 흔한 방법
* 조금 더 깨끗한 방법으로 데코레이터가 있음!
1 | from functools import wraps |
해당 모듈을 임포트하고 시간 측정하고 싶은 함수 위에 @timefn 을 붙이면 된다.
이 방법 외에 timeit을 사용하는 방법이 있다.
python3 -m timeit -n 5 -r 5 -s "import julia1" "julia1.calc_pure_python(desired_width=1000, max_iterations=300, draw_output=True)"
이런식으로 실행시킬 수 있다.
실행시키고자 하는 함수가 모듈 안에 정의되어 있으므로 -s 옵션을 통해 모듈 임포트가 필요하다.
-r 5는 반복 횟수, -n 5는 각 검사에서의 반복 후 평균(?)을 의미한다.
IPython의 경우 %timeit 매직 명령어가 가능하다. 바로 함수 호출을 하면 된다.
디폴트는 5번 씩 10회 반복 수행이다
쨌든 여러번 시도 후 베스트를 출력해주는 도구이다 (안정적인 가장 빠른 값을 얻기 위한 목적)
편차가 크다면 안정적인 결과 얻을 때 까지 반복할 필요가 있다.
* 백그라운드의 다양한 작업은 CPU와 디스크 자원에 무작위 영향을 주기 때문에 (편차 일으킴) 측정 시 다른 자원의 간섭이 없는지 체크해보는 것도 좋다.
또, 유닉스의 time 도구를 사용할 수 있다.
- 이 명령어는 코드 내부 구조에 전혀 신경쓰지 않지만
- 경과된 시간(real) 외에도 CPU가 커널 함수 외 작업을 처리하느라 소비한 시간(user), 커널 함수 수행 소비 시간(sys) 등을 측정할 수 있다.
- /user/bin/time -p python3 julia1.py
- 셸의 time이 아니다. (주의)
- -p 옵션을 줘야 real, user, sys에 대한 측정이 가능하다.
- /user/bin/time --verbose python3 julia1.py
- verbose 옵션을 주면 더 다양한 결과를 확인 할 수 있으며, "Major (requiring I/O) page faults" 가 가장 중요한 항목이라 할 수 있다. (OS가 RAM에서 필요한 데이터를 못찾아 디스크에서 페이지를 불러왔는지 여부를 나타낸다 - 속도를 느리게 하는 원인)




덧글