Python 가속 프로그램 실행 방법

문제.
프로그램 운행 이 너무 느 려 서 C 확장 이나 JIT 컴 파일 러 같은 복잡 한 기술 을 사용 하지 않 고 프로그램 운행 속 도 를 높이 고 싶 습 니 다.
해결 방안
프로그램 최적화 에 관 한 첫 번 째 준칙 은'최적화 하지 마'이 고 두 번 째 준칙 은'중요 하지 않 은 부분 을 최적화 하지 마'이다.만약 당신 의 프로그램 운행 이 느리다 면,우선 14.13 소절 의 기술 을 사용 하여 먼저 그것 에 대해 성능 테스트 를 해서 문제점 을 찾 아야 한다.
일반적으로 당신 은 프로그램 이 메모리 의 데이터 처리 순환 과 같은 몇 개의 핫 이 슈 위치 에서 많은 시간 을 소비 한 것 을 발견 할 수 있 습 니 다.일단 이러한 점 을 찾 으 면 다음 과 같은 실 용적 인 기술 을 사용 하여 프로그램 운행 을 가속 화 할 수 있다.
사용 함수
많은 프로그래머 들 이 처음에는 Python 언어 로 간단 한 스 크 립 트 를 썼 다.스 크 립 트 를 작성 할 때 구조 가 없 는 코드 를 쓰 는 것 에 익숙 합 니 다.예 를 들 어:

# somescript.py

import sys
import csv

with open(sys.argv[1]) as f:
   for row in csv.reader(f):

     # Some kind of processing
     pass
이렇게 정 의 된 전체 범위 의 코드 가 함수 에서 실행 되 는 것 보다 훨씬 느리다 는 것 을 아 는 사람 은 거의 없다.이러한 속도 차 이 는 국부 변수 와 전역 변수의 실현 방식 때문이다.따라서 프로그램 을 더 빨리 실행 시 키 려 면 스 크 립 트 문 구 를 함수 에 넣 으 면 됩 니 다.

# somescript.py
import sys
import csv

def main(filename):
  with open(filename) as f:
     for row in csv.reader(f):
       # Some kind of processing
       pass

main(sys.argv[1])
속도 의 차 이 는 실제 실행 되 는 프로그램 에 달 려 있 지만 경험 에 따라 함 수 를 사용 하여 15-30%의 성능 향상 을 가 져 오 는 것 은 흔 한 일이 다.
가능 한 한 속성 접근 을 제거 합 니 다.
매번 점(.)조작 자 를 사용 하여 속성 에 접근 할 때마다 추가 비용 을 가 져 옵 니 다.이것 은 특정한 방법 을 촉발 할 수 있다.예 를 들 어__getattribute__() __getattr__(),이런 방법 은 사전 조작 을 할 수 있다.
보통from module import name와 같은 가 져 오기 형식 과 바 인 딩 방법 을 사용 할 수 있 습 니 다.다음 코드 세 션 이 있다 고 가정 하 십시오.

import math

def compute_roots(nums):
  result = []
  for n in nums:
    result.append(math.sqrt(n))
  return result

# Test
nums = range(1000000)
for n in range(100):
  r = compute_roots(nums)
우리 기계 에서 테스트 할 때 이 프로그램 은 약 40 초 를 썼 다.지금 우 리 는compute_roots() 함 수 를 다음 과 같이 수정 합 니 다.

from math import sqrt

def compute_roots(nums):

  result = []
  result_append = result.append
  for n in nums:
    result_append(sqrt(n))
  return result
수 정 된 버 전의 실행 시간 은 대략 29 초 입 니 다.유일한 차이 점 은 속성 접근 을 없 애 는 것 이다.sqrt() 로 대체 했다math.sqrt() .4567914)방법 은 부분 변수The result.append() 에 부여 되 고 내부 순환 에서 사용 합 니 다.
그러나 이러한 변 화 는 대량의 중복 코드 에서 만 의미 가 있다.예 를 들 어 순환 이다.따라서 이런 최적화 도 특정 지역 에서 만 사용 되 어야 한다.
부분 변수 이해
이전에 언급 한 바 와 같이 국부 변 수 는 전역 변수 보다 운행 속도 가 빠르다.잦 은 접근 이름 에 대해 서 는 이 이름 을 부분 변수 로 바 꾸 면 프로그램 운행 을 가속 화 할 수 있 습 니 다.예 를 들 어 이전에 result_append 함수 에 대해 수정 한 버 전 을 보 세 요.

import math

def compute_roots(nums):
  sqrt = math.sqrt
  result = []
  result_append = result.append
  for n in nums:
    result_append(sqrt(n))
  return result
이 버 전에 서compute_roots() 모듈 에서 꺼 내 부분 변수 에 넣 었 습 니 다.이 코드 를 실행 하 는 데 25 초 정도 걸 립 니 다.이 추가 가속 원인 은 국부 변수sqrt에 대한 검색 이 전역 변수math보다 빠 르 기 때문이다.
클래스 의 속성 접근 도 이 원리 에 적용 된다.일반적으로 self.name 같은 값 을 찾 는 것 은 국부 변수 에 접근 하 는 것 보다 느 립 니 다.내부 순환 에서 자주 방문 해 야 할 속성 을 부분 변수 에 넣 을 수 있 습 니 다.예 를 들 면:

# Slower
class SomeClass:
  ...
  def method(self):
     for x in s:
       op(self.value)

# Faster
class SomeClass:

  ...
  def method(self):
     value = self.value
     for x in s:
       op(value)
불필요 한 추상 을 피하 다
언제든지 추가 처리 층(예 를 들 어 장식 기,속성 접근,설명 기)을 사용 하여 코드 를 포장 할 때 프로그램 운행 이 느 려 집 니 다.예 를 들 어 다음 과 같은 종 류 를 보 세 요.

class A:
  def __init__(self, x, y):
    self.x = x
    self.y = y
  @property
  def y(self):
    return self._y
  @y.setter
  def y(self, value):
    self._y = value
현재 간단 한 테스트 를 진행 합 니 다:

>>> from timeit import timeit
>>> a = A(1,2)
>>> timeit('a.x', 'from __main__ import a')
0.07817923510447145
>>> timeit('a.y', 'from __main__ import a')
0.35766440676525235
>>>
이 를 통 해 알 수 있 듯 이 방문 속성 y 는 속성 x 에 비해 조금 느 린 것 이 아니 라 4.5 배 정도 느 린 것 으로 나 타 났 다.성능 에 신경 을 쓴다 면 Y 의 속성 접근 기 에 대한 정의 가 정말 필요 한 지 다시 살 펴 봐 야 합 니 다.필요 없다 면 간단 한 속성 을 사용 하 세 요.다른 프로 그래 밍 언어 만 getter/setter 함 수 를 사용 해 야 하기 때문에 코드 스타일 을 수정 할 필요 가 없습니다.
내 장 된 용기 사용 하기
내 장 된 데이터 형식,예 를 들 어 문자열,모듈,목록,집합 과 사전 은 모두 C 로 이 루어 져 매우 빨리 실 행 됩 니 다.새로운 데이터 구조(예 를 들 어 링크 목록,밸 런 스 트 리 등)를 스스로 실현 하고 싶다 면 성능 적 으로 내 장 된 속 도 를 달성 하 는 것 은 거의 불가능 하 므 로 내 장 된 것 을 순 순 히 사용 하 세 요.
불필요 한 데이터 구 조 를 만 들 거나 복사 하 는 것 을 피하 십시오.
프로그래머 들 은 불필요 한 데이터 구 조 를 만 들 려 고 한다.예 를 들 어 누군가가 아래 와 같이 쓸 수 있다.

values = [x for x in sequence]
squares = [x*x for x in values]
아마도 여기 서 생각 하 는 것 은 우선 일부 값 을 목록 에 수집 한 다음 에 목록 으로 유도 하여 작업 을 수행 하 는 것 일 것 이다.그러나 첫 번 째 목록 은 전혀 필요 없습니다.간단하게 아래 와 같이 쓸 수 있 습 니 다.

squares = [x*x for x in sequence]
이와 관련 하여 Python 의 공유 데이터 체제 에 대해 지나치게 고 집 스 러 운 프로그램 이 쓴 코드 도 주의해 야 한다.어떤 사람들 은 Python 의 메모리 모델 을 잘 이해 하거나 신뢰 하지 못 하고sqrt같은 함 수 를 남용 합 니 다.보통 이 코드 들 에 서 는 복사 작업 을 없 앨 수 있다.
토론 하 다.
최적화 하기 전에 사용 하 는 알고리즘 을 먼저 연구 할 필요 가 있다.복잡 도가 O(n log n)인 알고리즘 을 선택 하 는 것 은 복잡 도가 O(n**2)인 알고리즘 을 조정 하 는 것 보다 성능 향상 이 훨씬 크다.
만약 당신 이 그래도 최 적 화 를 해 야 한다 고 생각한다 면,전체적으로 고려 하 세 요.일반적인 준칙 으로서 프로그램의 모든 부분 을 최적화 하지 마라.왜냐하면 이런 수정 은 코드 를 읽 고 이해 하기 어렵 기 때문이다.내부 순환 같은 성능 병목 이 생기 는 곳 을 최적화 하 는 데 전념 해 야 한다.
너 는 작은 최적화 결과 에 도 주의해 야 한다.예 를 들 어 다음 사전 을 만 드 는 두 가지 방식 을 고려 합 니 다.

a = {
  'name' : 'AAPL',
  'shares' : 100,
  'price' : 534.22
}

b = dict(name='AAPL', shares=100, price=534.22)
뒤의 글 씨 는 좀 더 간결 하 다.그러나 이 두 코드 세 션 을 성능 테스트 와 비교 하면 사용sqrt방식 이 3 배 느 린 것 으로 나 타 났 다.이것 을 보고 당신 은 충동 적 으로 모든 사용copy.deepcopy() 코드 를 첫 번 째 로 바 꾸 었 습 니까?똑똑 하지 못 한 프로그래머 는 내부 순환 같은 그 가 주목 해 야 할 부분 에 만 관심 을 갖 는 다.다른 곳 에 서 는 이런 성능 손실 에 아무런 영향 이 없다.
만약 에 당신 의 최적화 요구 가 비교적 높 고 이 절의 이런 간단 한 기술 이 만족 하지 못 한다 면 실시 간 컴 파일(JIT)기술 을 바탕 으로 하 는 도 구 를 연구 할 수 있 습 니 다.예 를 들 어 PyPy 프로젝트 는 Python 해석 기의 또 다른 실현 입 니 다.프로그램 이 실행 되 고 자주 실행 되 는 부분 에 대해 이 컴퓨터 코드 를 생 성 하 는 것 을 분석 할 것 입 니 다.그것 은 때때로 성능 을 크게 향상 시 킬 수 있 고 보통 C 코드 의 속도 에 접근 할 수 있다.그러나 안 타 깝 게 도 이 책 을 쓸 때 까지 PyPy 는 Python 3 를 완전히 지지 하지 못 하기 때문에 이것 은 당신 이 앞으로 연구 해 야 할 것 입 니 다.Numba 프로젝트 도 고려 할 수 있 습 니 다.Numba 는 장식 기 를 사용 하여 Python 함 수 를 선택 하여 최적화 할 때 동적 컴 파일 러 입 니 다.이 함수 들 은 LLVM 을 사용 하여 로 컬 기계 코드 로 컴 파일 됩 니 다.그것 역시 성능 을 크게 향상 시 킬 수 있다.그러나 PyPy 와 마찬가지 로 Python 3 에 대한 지 지 는 아직 실험 단계 에 머 물 러 있다.
마지막 으로 나 는 John Ousterhout 가 한 말 을 인용 하여 결말 로 삼 았 다."가장 좋 은 성능 최 적 화 는 일 을 하지 않 고 업무 상태 로 이동 하 는 것 이다."네가 정말 최적화 가 필요 할 때 까지 다시 그것 을 고려 해라.프로그램의 정확 한 운행 을 확보 하 는 것 이 일반적으로 그것 을 실행 시 키 는 것 보다 더 중요 하 다(적어도 시작은 이렇다).
이상 은 Python 가속 프로그램 이 실행 되 는 방법 에 대한 상세 한 내용 입 니 다.Python 가속 프로그램 실행 에 관 한 자 료 는 다른 관련 글 을 주목 하 십시오!

좋은 웹페이지 즐겨찾기