
How I Speed Up My Python Scripts by 300%
파이썬 스크립트 속도를 300% 높이는 방법
배우면 후회하지 않을 것입니다.
방금 큰 데이터 세트를 처리해야 하는 Python 스크립트를 작성했던 때가 아직도 기억납니다. 작은 프로젝트였지만 그 많은 데이터를 처리하려면 한참을 기다려야 했습니다.
몇 분이면 끝낼 수 있는 작업이 몇 시간이 걸립니다.
그러다 뭔가 잘못되었다는 것을 깨달았습니다. 제 코드가 최적화되지 않았기 때문에 여러 번 시도한 끝에 코드를 최적화하는 방법을 배웠습니다. 그 결과 스크립트 속도가 300% 빨라졌습니다.
이제부터, 그 시기 한 일을 단계별로 이해해 봅시다.

Profile Your Code First
1. 먼저 코드 프로파일링하기
우선, 코드의 어느 부분이 속도 저하를 일으키는지 파악해야 합니다. 하지만 그 부분을 추측할 필요는 없습니다.
파이썬에서는 프로그램에서 가장 많은 시간이 걸리는 부분을 파악하는 데 도움이 되는 cProfile 을 사용할 수 있습니다.
어떻게 사용하는지 알아봅시다.
import cProfile
def my_script():
# Your code here
pass
cProfile.run('my_script()')
각 함수가 얼마나 많은 시간을 소비하는지 자세히 분석할 수 있습니다.
import cProfile
def my_script():
total = 0
for i in range(1, 1000000):
total += i
return total
cProfile.run('my_script()')
# 실행 결과 예시
4 function calls in 0.120 seconds
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.120 0.120 0.120 0.120 profiling.py:4(my_script)
1 0.000 0.000 0.120 0.120 <string>:1(<module>)
1 0.000 0.000 0.120 0.120 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {built-in method builtins.sum}
- ncalls: 함수가 호출된 횟수
- tottime: 해당 함수에서 소비된 총 실행 시간 (다른 함수 호출 포함 X)
- percall: tottime / ncalls (호출당 평균 실행 시간)
- cumtime: 해당 함수가 호출한 다른 함수의 실행 시간을 포함한 총 실행 시간
- filename:lineno(function): 함수가 정의된 파일과 줄 번호
제 스크립트에서 cProfile을 사용했을 때, 스크립트 런타임의 80%가 단 두 개의 함수에 소요되는 것을 발견했습니다. 그래서 이 두 함수를 최적화하기로 결정했습니다.

Use Built-in Functions
2. 내장 기능 사용
여러분은 이미 파이썬 내장 함수가 C로 작성되었기 때문에 파이썬으로 작성하는 함수보다 실행 속도가 훨씬 빠르다는 것을 알고 있습니다.
코드에서는 목록에 숫자를 추가하기 위해 for 루프를 사용하고 있었습니다.
total = 0
for num in my_list:
total += num
-
- Python 반복문을 사용해 각 항목을 순회합니다
- 각 숫자마다 변수에 더하는 연산을 수행합니다
- 일반 Python 인터프리터 수준에서 실행됩니다
- 상대적으로 느립니다
그래서 파이썬의 내장 함수 sum으로 대체했습니다.
total = sum(my_list)
-
- Python 내장 함수를 사용합니다
- C언어로 구현되어 있어 최적화되어 있습니다
- 내부적으로 더 효율적인 알고리즘을 사용합니다
- 실행 시간이 약 50% 감소합니다
Python의 내장 함수들(sum(), max(), min() 등)은 C로 구현되어 있어 일반 Python 코드보다 훨씬 빠릅니다. 가능하면 이러한 내장 함수를 활용하는 것이 코드의 가독성과 성능을 모두 향상시키는 좋은 방법입니다.
이렇게 하면 코드의 해당 부분의 런타임이 50% 줄어듭니다.
Use List Comprehensions Instead of Loops
3. 루프 대신 목록 이해 사용
루프를 작성하기 쉽지만 항상 가장 빠른 것은 아니라는 것을 알고 있습니다. for loop를 사용하여 기존 목록에서 새 목록을 만드는 코드가 있습니다.
첫 번째 방식: 일반 for 반복문
new_list = []
for item in old_list:
if item > 10:
new_list.append(item)
-
- 빈 리스트를 먼저 생성합니다
- 각 항목을 반복하면서 조건을 확인합니다
- 조건을 만족하는 항목만 .append() 메서드로 리스트에 추가합니다
- 여러 단계의 연산이 필요합니다
이 코드를 목록 이해로 대체했습니다.
두 번째 방식: 리스트 컴프리헨션
new_list = [item for item in old_list if item > 10]
-
- 한 줄로 간결하게 표현됩니다
- 내부적으로 최적화되어 있어 약 2배 더 빠릅니다
- Python 인터프리터가 더 효율적으로 처리합니다
- 가독성이 더 좋습니다
이 변경으로 인해 위의 코드가 2배 빨라졌습니다.

Avoid Global Variables
4. 전역 변수 피하기
이 사실을 알고 계신지 모르겠지만 전역 변수는 파이썬이 전역 변수의 값을 찾기 위해 많은 범위를 확인해야 하므로 스크립트 속도가 느려질 수 있습니다.
큰 함수에서 전역 변수 counter를 사용했습니다.
첫 번째 방식: 전역 변수 사용
counter = 0
def count_items(items):
global counter
for item in items:
counter += 1
-
- counter는 전역 변수로 선언됨
- global 키워드로 함수 내에서 전역 변수에 접근
- 모든 함수와 코드에서 접근 가능
- 변수 조회와 수정 시 전역 네임스페이스를 검색해야 함
- 다른 함수나 코드에서 의도치 않게 값이 변경될 수 있음
하지만 이 변수를 다음과 같이 함수 내부로 이동하기로 결정했습니다.
두 번째 방식: 지역 변수 사용
def count_items(items):
counter = 0
for item in items:
counter += 1
-
- counter는 함수 내부의 지역 변수로 선언됨
- 함수 내부에서만 접근 가능
- 지역 네임스페이스에서 직접 접근하므로 더 빠름
- 다른 코드에 영향을 주지 않음
- 함수가 호출될 때마다 새로 초기화됨
이 변경 사항은 스크립트 속도를 높이는 데 많은 도움이 됩니다.

Replace Regular Loops with NumPy
5. 일반 루프를 NumPy로 바꾸기
처음에는 숫자 데이터를 처리하기 위해 Python 리스트를 사용했지만, 이 작업을 위해서는 Numpy를 사용해야 한다는 것을 깨달았습니다.
예를 들어 목록의 각 항목에 2를 곱해야 했는데, Numpy를 사용하기 전에는 이 작업이 마음에 들었습니다.
result = [x * 2 for x in my_list]
-
- 순수 Python으로 구현됨
- 각 항목을 개별적으로 처리 (반복문 사용)
- Python 인터프리터 수준에서 실행됨
- 대용량 데이터 처리 시 상대적으로 느림
Numpy를 사용하니 이렇게 되었습니다.
import numpy as np
array = np.array(my_list)
result = array * 2
-
- C언어로 구현된 최적화된 코드 사용
- 전체 배열에 대해 한 번에 연산 수행 (벡터화)
- 내부적으로 최적화된 C 코드 실행
- 대용량 데이터 처리 시 약 10배 빠름
그리고 이 Numpy 버전은 큰 목록이 있는 경우 10배 더 빠르게 실행되는데, 이는 Numpy가 C로 빌드되었기 때문입니다.
Use Generators for Large Data
6. 대용량 데이터에 생성기 사용
해당 스크립트에는 대규모 데이터 집합을 처리하는 함수가 있었습니다. 중간 결과를 저장하기 위해 목록을 사용했는데, 대부분의 메모리를 사용하면서 속도가 느려졌습니다.
첫 번째 방식: 리스트 컴프리헨션 (대괄호 [])
squares = [x**2 for x in range(1_000_000)]
-
- 모든 결과값을 한 번에 메모리에 생성합니다
- 1,000,000개의 제곱 값이 모두 메모리에 저장됩니다
- 많은 메모리를 사용합니다
- 전체 리스트에 즉시 접근 가능합니다
그러다 항목을 한 번에 처리하지 않고 순차적으로 처리하는 제너레이터를 사용하기 시작했습니다.
두 번째 방식: 제너레이터 표현식 (소괄호 ())
squares = (x**2 for x in range(1_000_000))
-
- 실제 사용할 때마다 값을 하나씩 생성합니다
- 모든 값을 메모리에 저장하지 않습니다
- 메모리 사용량이 현저히 줄어듭니다
- 필요한 시점에 데이터를 생성하는 '지연 평가(lazy evaluation)' 방식입니다
이렇게 하면 메모리 사용량을 줄여 스크립트를 향상시키는 데 도움이 됩니다.

Parallel Processing with multiprocessing
7. 멀티 프로세싱을 통한 병렬 처리
가장 좋은 결과는 다중 CPU 코어에 대해 알게 되었을 때 나왔습니다.
아시다시피 기본적으로 파이썬은 단일 코어에서 실행됩니다. 하지만 multiprocessing 라이브러리를 사용하면 사용 가능한 다른 코어에 작업을 분할할 수 있습니다.
어떻게 했는지 말씀드리겠습니다.
from multiprocessing import Pool
def process_data(item):
# Your processing logic here
return item * 2
if __name__ == "__main__":
with Pool() as pool:
results = pool.map(process_data, my_list)
- multiprocessing 모듈의 Pool 클래스를 사용해 여러 프로세스를 생성합니다
- pool.map() 함수로 데이터 리스트(my_list)의 각 항목을 여러 프로세스에 분배합니다
- 각 프로세스가 동시에 process_data() 함수를 실행합니다
- CPU의 여러 코어를 활용해 작업을 병렬로 처리합니다
- 순차 처리 대비 처리 속도가 최대 100% 향상됩니다
이 한 가지 변경으로 일부 작업을 병렬로 실행할 수 있게 되어 스크립트 속도가 100% 향상되었습니다.
Avoid Repeating Work
8. 반복 작업 방지
이전에는 같은 결과를 반복해서 계산하는 함수가 있었습니다.
for item in my_list:
result = expensive_function(item)
print(result)
-
- 매번 expensive_function()을 호출합니다
- 같은 입력값에 대해서도 반복적으로 계산합니다
- 시간과 리소스가 낭비됩니다
하지만 그 결과를 단일 변수에 저장하기로 결정했습니다.
cache = {}
for item in my_list:
if item not in cache:
cache[item] = expensive_function(item)
print(cache[item])
-
- 계산 결과를 cache 딕셔너리에 저장합니다
- 같은 입력값에 대해서는 저장된 결과를 재사용합니다
- 중복 계산을 피해 처리 시간을 크게 단축합니다
이 기술을 메모화라고 부를 수 있으며 시간을 많이 절약하는 데 도움이 됩니다.

Optimize Imports
9. 가져오기 최적화
이전에는 라이브러리에서 하나의 함수라도 사용하려면 라이브러리 전체를 가져와야 했습니다.
import pandas
result = pandas.read_csv("data.csv")
-
- 라이브러리 전체를 가져옵니다
- 함수를 사용할 때 pandas.함수명 형태로 사용합니다
- 메모리에 전체 라이브러리가 로드됩니다
하지만 저는 방식을 바꾸기로 결심하고 필요한 라이브러리에서 해당 기능을 가져왔습니다.
from pandas import read_csv
result = read_csv("data.csv")
-
- 필요한 함수만 선택적으로 가져옵니다
- 함수를 직접 이름으로 사용할 수 있습니다
- 필요한 부분만 로드하므로 스크립트 시작 시간이 단축됩니다
- 실행 속도가 향상됩니다
이 방법은 스크립트 속도를 높일 뿐만 아니라 스크립트 시작 시간도 단축하는 데 도움이 되었습니다.
Use the Latest Version of Python
10. 최신 버전의 Python 사용
이전에는 이전 버전의 Python을 사용하고 있었습니다. 그래서 최신 버전으로 업그레이드한 후 코드 한 줄도 변경하지 않고도 스크립트의 속도가 눈에 띄게 빨라졌습니다.
제가 스크립트 속도를 높일 수 있다면 여러분도 할 수 있습니다. 다만 인내심과 실험 의지가 필요합니다.
다음에 코딩할 때마다 이 단계를 시도해보고 이 방법이 도움이 되는지 확인해 보세요.

[코몬랩] 위기 인식과 허구적 작용의 연속성 - 파주 운정 목동동 코딩 교육
위기 인식과 허구적 작용의 연속성 위기를 인식하는 과정은 단순한 객관적 사실의 인지가 아니라, 개인의 경험과 사고방식에 의해 형성되는 허구적 작용의 연속일 수 있다. 즉, 사람들
kayoko.tistory.com
[코몬랩] 돈의 심리학이 주는 영원한 교훈 20가지 - 파주 운정 목동동 코딩 교육
. 20 Evergreen Lessons from The Psychology of Money돈의 심리학이 주는 영원한 교훈 20가지 같은 지식을 가지고 있음에도 불구하고 어떤 사람들은 돈을 벌고 어떤 사람들은 모든 것을 잃는 이유
kayoko.tistory.com
[코몬랩] 소셜 미디어 전략: 콘텐츠 번아웃을 방지하는 10가지 방법 - 파주 운정 목동동 코딩 교육
Social Media Strategy: 10 Ways to Avoid Content Burnout소셜 미디어 전략: 콘텐츠 번아웃을 방지하는 10가지 방법 소셜 미디어 마케터나 콘텐츠 제작자로 일하다 보면 번아웃이 찾아올 위험이 있습니다
kayoko.tistory.com
#파주, #운정, #코딩, #코딩교육, #프로그램, #프로그래밍, #코드몬스터랩, #헬로우잡스, #안녕잡스
#일산, #온라인, #파주운정신도시, #ai, #교육, #AI직업, #코딩학원, #맞춤교육, #헬로잡스, #목동동
파주, 운정, 코딩, 코딩교육, 프로그램, 프로그래밍, 코드몬스터랩, 헬로우잡스, 안녕잡스
일산, 온라인, 파주운정신도시, ai, 교육, AI직업, 코딩학원, 맞춤교육, 헬로잡스,목동동
과정을 돋보이게 하는 교육
코드몬스터랩
교육상담문의 : 010-7912-4437
참조 : https://medium.com/python-in-plain-english/how-i-speed-up-my-python-scripts-by-300-31030219a6d5