더 나은 성능을 위해 Python 스크립트를 최적화하는 방법

Deo Na Eun Seongneung Eul Wihae Python Seukeulibteuleul Choejeoghwahaneun Bangbeob



더 나은 성능을 위해 Python 스크립트를 최적화하려면 코드의 병목 현상을 식별하고 해결하여 더 빠르고 효율적으로 실행되도록 해야 합니다. Python은 오늘날 데이터 분석, ML 프로젝트(머신러닝), 웹 개발 등을 포함한 수많은 애플리케이션에서 사용되는 인기 있고 강력한 프로그래밍 언어입니다. Python 코드 최적화는 더 적은 코드 줄, 더 적은 메모리 또는 추가 리소스를 사용하여 활동을 수행할 때 개발자 프로그램의 속도와 효율성을 향상시키는 전략입니다. 크고 비효율적인 코드로 인해 프로그램 속도가 느려지고 클라이언트 만족도가 낮아지고 재정적 손실이 발생할 수 있으며 수정 및 문제 해결을 위해 더 많은 작업이 필요할 수 있습니다.

여러 작업이나 데이터 처리가 필요한 작업을 수행하는 동안 필요합니다. 따라서 일부 비효율적인 코드 블록과 기능을 교체하고 개선하면 다음과 같은 놀라운 결과를 얻을 수 있습니다.

  1. 애플리케이션 성능 향상
  2. 읽기 쉽고 체계적인 코드 만들기
  3. 오류 모니터링 및 디버깅을 더욱 단순화하세요.
  4. 상당한 계산 능력 등을 보존합니다.

코드 프로파일링

최적화를 시작하기 전에 속도를 저하시키는 프로젝트 코드 부분을 식별하는 것이 중요합니다. Python의 프로파일링 기술에는 cProfile 및 profile 패키지가 포함됩니다. 이러한 도구를 활용하여 특정 기능과 코드 줄이 얼마나 빨리 실행되는지 측정하세요. cProfile 모듈은 각 스크립트 기능을 실행하는 데 걸리는 시간을 자세히 설명하는 보고서를 생성합니다. 이 보고서는 느리게 실행되는 기능을 찾아서 개선하는 데 도움이 될 수 있습니다.







코드 조각:



수입 c프로필 ~처럼 CP
데프 계산합 ( 입력번호 ) :
sum_of_input_numbers = 0
~하는 동안 입력번호 > 0 :
sum_of_input_numbers + = 입력 개수 % 10
입력번호 // = 10
인쇄 ( '입력 번호의 모든 자릿수 합계는 'sum_of_input_numbers'입니다.' )
반품 sum_of_input_numbers
데프 main_func ( ) :
cP. 달리다 ( '합계 계산(9876543789)' )
만약에 __이름__ == '__기본__' :
main_func ( )

프로그램은 출력의 첫 번째 줄에 표시된 대로 총 5개의 함수 호출을 수행합니다. 각 함수 호출에 대한 세부 정보는 함수가 호출된 횟수, 함수의 전체 지속 시간, 호출당 지속 시간, 함수의 전체 시간(포함)을 포함하여 다음 몇 줄에 표시됩니다. 호출되는 모든 함수).

또한 프로그램은 프로그램이 모든 작업의 ​​실행 시간을 0.000초 이내에 완료했음을 보여주는 보고서를 프롬프트 화면에 인쇄합니다. 이는 프로그램이 얼마나 빠른지 보여줍니다.

올바른 데이터 구조 선택

성능 특성은 데이터 구조에 따라 다릅니다. 특히, 범용 저장소에 대해서는 목록보다 사전이 조회 속도가 더 빠릅니다. 귀하가 알고 있는 경우 귀하의 데이터에 대해 수행할 작업에 가장 적합한 데이터 구조를 선택하십시오. 다음 예에서는 데이터 구조의 요소가 존재하는지 여부를 확인하기 위해 동일한 프로세스에 대한 다양한 데이터 구조의 효율성을 조사합니다.

목록, 집합, 사전 등 각 데이터 구조에 요소가 있는지 확인하는 데 걸리는 시간을 평가하고 비교합니다.

OptimizeDataType.py:

수입 티메이 ~처럼 ㅜㅜ
수입 무작위의 ~처럼 Rndobj
# 정수 목록을 생성합니다.
무작위_데이터_목록 = [ rndobj. 랜딘트 ( 1 , 10000 ) ~을 위한 _ ~에 범위 ( 10000 ) ]
# 동일한 데이터로 세트를 만듭니다.
무작위_데이터_세트 = 세트 ( 무작위_데이터_목록 )

# 키와 동일한 데이터로 사전을 생성합니다.
obj_DataDictionary = { 하나에: 없음 ~을 위한 하나에 ~에 무작위_데이터_목록 }

# 검색할 요소(데이터에 존재함)
random_number_to_find = rndobj. 선택 ( 무작위_데이터_목록 )

# 목록에서 구성원을 확인하는 시간을 측정합니다.
목록_시간 = tt. 티메이 ( 람다 : 무작위_번호_찾기_찾기 ~에 무작위_데이터_목록 , 숫자 = 1000 )

# 집합의 구성원을 확인하는 시간을 측정합니다.
설정_시간 = tt. 티메이 ( 람다 : 무작위_번호_찾기_찾기 ~에 무작위_데이터_세트 , 숫자 = 1000 )

# 사전에 회원가입을 확인하는 시간을 측정
dict_time = tt. 티메이 ( 람다 : 무작위_번호_찾기_찾기 ~에 obj_DataDictionary , 숫자 = 1000 )

인쇄 ( 에프 '목록 회원 확인 시간: {list_time:.6f}초' )
인쇄 ( 에프 '멤버십 확인 시간 설정: {set_time:.6f}초' )
인쇄 ( 에프 '사전 멤버십 확인 시간: {dict_time:.6f}초' )

이 코드는 멤버십 검사를 수행할 때 목록, 세트 및 사전의 성능을 비교합니다. 일반적으로 집합과 사전은 해시 기반 조회를 사용하기 때문에 멤버십 테스트를 위한 목록보다 훨씬 빠르므로 평균 시간 복잡도는 O(1)입니다. 반면에 목록은 O(n) 시간 복잡도로 멤버십 테스트를 수행하는 선형 검색을 수행해야 합니다.

  자동으로 생성된 컴퓨터 설명의 스크린샷

루프 대신 내장 함수 사용

Python의 다양한 내장 함수 또는 메소드를 사용하여 필터링, 정렬, 매핑과 같은 일반적인 작업을 수행할 수 있습니다. 루프를 생성하는 대신 이러한 루틴을 사용하면 성능이 최적화되는 경우가 많기 때문에 코드 속도를 높이는 데 도움이 됩니다.

일반적인 작업에 내장된 함수(예: map(), filter() 및 sorted())를 활용하여 사용자 정의 루프 생성 성능을 비교하기 위해 몇 가지 샘플 코드를 작성해 보겠습니다. 다양한 매핑, 필터링 및 정렬 방법이 얼마나 잘 수행되는지 평가하겠습니다.

내장함수.py:

수입 티메이 ~처럼 ㅜㅜ
# 숫자 목록의 샘플 목록
숫자_목록 = 목록 ( 범위 ( 1 , 10000 ) )

# 루프를 사용하여 숫자 목록을 제곱하는 함수
데프 square_using_loop ( 숫자_목록 ) :
square_result = [ ]
~을 위한 하나에 ~에 숫자_목록:
square_result. 추가 ( 하나에 ** 2 )
반품 square_result
# 루프를 사용하여 짝수_목록을 필터링하는 함수
데프 filter_even_using_loop ( 숫자_목록 ) :
필터_결과 = [ ]
~을 위한 하나에 ~에 숫자_목록:
만약에 1%에 2 == 0 :
필터_결과. 추가 ( 하나에 )
반품 필터_결과
# 루프를 사용하여 숫자 목록을 정렬하는 함수
데프 sort_using_loop ( 숫자_목록 ) :
반품 정렬됨 ( 숫자_목록 )
# map()을 사용하여 숫자 목록을 제곱하는 시간을 측정합니다.
지도_시간 = tt. 티메이 ( 람다 : 목록 ( 지도 ( 람다 x: x ** 2 , 숫자_목록 ) ) , 숫자 = 1000 )
# filter()를 사용하여 짝수_목록을 필터링하는 시간을 측정합니다.
필터 시간 = tt. 티메이 ( 람다 : 목록 ( 필터 ( 람다 x: x% 2 == 0 , 숫자_목록 ) ) , 숫자 = 1000 )
# sorted()를 사용하여 숫자 목록을 정렬하는 데 걸리는 시간을 측정합니다.
sorted_time = tt. 티메이 ( 람다 : 정렬됨 ( 숫자_목록 ) , 숫자 = 1000 )
# 루프를 사용하여 숫자 목록을 제곱하는 시간을 측정합니다.
loop_map_time = tt. 티메이 ( 람다 : square_using_loop ( 숫자_목록 ) , 숫자 = 1000 )
# 루프를 사용하여 짝수_목록을 필터링하는 시간을 측정합니다.
loop_filter_time = tt. 티메이 ( 람다 : filter_even_using_loop ( 숫자_목록 ) , 숫자 = 1000 )
# 루프를 사용하여 숫자 목록을 정렬하는 데 걸리는 시간을 측정합니다.
loop_sorted_time = tt. 티메이 ( 람다 : sort_using_loop ( 숫자_목록 ) , 숫자 = 1000 )
인쇄 ( '번호 목록에는 10000개의 요소가 포함되어 있습니다.' )
인쇄 ( 에프 'Map() 시간: {map_time:.6f}초' )
인쇄 ( 에프 '필터() 시간: {filter_time:.6f}초' )
인쇄 ( 에프 '정렬() 시간: {sorted_time:.6f}초' )
인쇄 ( 에프 '루프(맵) 시간: {loop_map_time:.6f}초' )
인쇄 ( 에프 '루프(필터) 시간: {loop_filter_time:.6f}초' )
인쇄 ( 에프 '루프(정렬) 시간: {loop_sorted_time:.6f}초' )

우리는 내장 함수(map(), filter() 및 sorted())가 이러한 일반적인 작업에 대한 사용자 정의 루프보다 빠르다는 것을 관찰할 것입니다. Python에 내장된 함수는 이러한 작업을 수행하기 위한 보다 간결하고 이해하기 쉬운 접근 방식을 제공하며 성능에 고도로 최적화되어 있습니다.

루프 최적화

루프 작성이 필요한 경우 속도를 높이기 위해 수행할 수 있는 몇 가지 기술이 있습니다. 일반적으로 range() 루프는 뒤로 반복하는 것보다 빠릅니다. 이는 range()가 목록을 반전하지 않고 반복자를 생성하기 때문입니다. 이는 긴 목록에 대해 비용이 많이 드는 작업이 될 수 있습니다. 또한 range()는 메모리에 새 목록을 만들지 않기 때문에 메모리를 덜 사용합니다.

OptimizeLoop.py:

수입 티메이 ~처럼 ㅜㅜ
# 숫자 목록의 샘플 목록
숫자_목록 = 목록 ( 범위 ( 1 , 100000 ) )
# 목록을 역순으로 반복하는 함수
데프 loop_reverse_iteration ( ) :
결과_역 = [ ]
~을 위한 제이 ~에 범위 ( 오직 ( 숫자_목록 ) - 1 , - 1 , - 1 ) :
결과_역. 추가 ( 숫자_목록 [ 제이 ] )
반품 결과_역
# range()를 사용하여 목록을 반복하는 함수
데프 loop_range_iteration ( ) :
결과_범위 = [ ]
~을 위한 케이 ~에 범위 ( 오직 ( 숫자_목록 ) ) :
결과_범위. 추가 ( 숫자_목록 [ 케이 ] )
반품 결과_범위
# 역반복을 수행하는 데 걸리는 시간을 측정합니다.
역방향 시간 = tt. 티메이 ( loop_reverse_iteration , 숫자 = 1000 )
# 범위 반복을 수행하는 데 걸리는 시간을 측정합니다.
범위_시간 = tt. 티메이 ( loop_range_iteration , 숫자 = 1000 )
인쇄 ( '번호 목록에는 100000개의 레코드가 포함되어 있습니다.' )
인쇄 ( 에프 '역방향 반복 시간: {reverse_time:.6f}초' )
인쇄 ( 에프 '범위 반복 시간: {range_time:.6f}초' )

불필요한 함수 호출을 피하세요

함수가 호출될 때마다 약간의 오버헤드가 발생합니다. 불필요한 함수 호출을 피하면 코드가 더 빠르게 실행됩니다. 예를 들어, 값을 계산하는 함수를 반복적으로 실행하기보다는 계산 결과를 변수에 저장해 활용해보세요.

프로파일링 도구

코드 성능에 대해 자세히 알아보려면 내장된 프로파일링 외에도 cProfile, Pyflame 또는 SnakeViz와 같은 외부 프로파일링 패키지를 활용할 수 있습니다.

캐시 결과

코드에서 비용이 많이 드는 계산을 수행해야 하는 경우 시간을 절약하기 위해 결과를 캐싱하는 것을 고려할 수 있습니다.

코드 리팩토링

코드를 더 쉽게 읽고 유지 관리할 수 있도록 코드를 리팩터링하는 것은 때로는 코드 최적화에 필요한 부분입니다. 더 빠른 프로그램이 더 깨끗할 수도 있습니다.

JIT(Just-in-Time 컴파일) 사용

PyPy 또는 Numba와 같은 라이브러리는 특정 유형의 Python 코드 속도를 크게 향상시킬 수 있는 JIT 컴파일을 제공할 수 있습니다.

Python 업그레이드

최신 버전에는 성능 향상이 포함되는 경우가 많으므로 최신 버전의 Python을 사용하고 있는지 확인하세요.

병렬성과 동시성

병렬화할 수 있는 프로세스의 경우 다중 처리, 스레딩 또는 asyncio와 같은 병렬 및 동기화 기술을 조사하십시오.

벤치마킹과 프로파일링이 최적화의 주요 동인이라는 점을 기억하세요. 성능에 가장 큰 영향을 미치는 코드 영역을 개선하는 데 집중하고 개선 사항을 지속적으로 테스트하여 더 많은 결함을 발생시키지 않고 원하는 효과가 있는지 확인하십시오.

결론

결론적으로 Python 코드 최적화는 성능 및 리소스 효율성 향상에 매우 중요합니다. 개발자는 적절한 데이터 구조 선택, 내장 기능 활용, 추가 루프 감소, 효과적인 메모리 관리 등의 다양한 기술을 사용하여 Python 애플리케이션의 실행 속도와 응답성을 크게 높일 수 있습니다. 지속적인 벤치마킹 및 프로파일링은 코드 개선이 실제 성능 요구 사항과 일치하도록 최적화 노력을 지시해야 합니다. 장기적인 프로젝트 성공을 보장하고 새로운 문제가 발생할 가능성을 낮추려면 코드 최적화가 코드 가독성 및 유지 관리 목표와 지속적으로 균형을 이루어야 합니다.