본문 바로가기
파이썬

파이썬_최적화튜닝전략

by 혜룐 2016. 9. 2.

일부 내용만 공유합니다.


 

  1. 내장타입을 사용하라.
    1. 내장 튜플, 리스트, 집합, 사전타입은 C로 구현되어있고, 인터프리터에 가장 잘 튜닝되어있는 자료구조이다.
  2. 계층을 추가하지 않는다.
    1. first  는 dict() 함수호출이 있기 때문에 수행속도가 조금 더 느리다. 수백만개의 dict 을 생성하는 경우라면 second 가 빠르다.

      def test_perf_dict(self):
          first = timeit("s = dict(name='catherine', shares=100, price=100)" )
          print(first)
          ## 0.291458129883
       
          second = timeit("s = {'name':'catherine', 'shares':100, 'price':100}" )
          print(second)
          ## 0.140990972519
  3. 클래스와 인스터스가 dict을 토대로 만들어진것을 안다. = class 만이 데이터를 저장하는 유일한 방법이 아니다!
    1. 사용자 정의클래스와 인스턴스는 dict 를 사용해 만들어진다. 따라서 단지 데이터를 저장하기 위한 간단한 자료구조를 원하는 거라면, class를 정의한느 것보다는 dict 를 사용하는 것이 더 효율적일수 있다. 
      1. 인스턴스 데이터를 검색하고 설정하며 지우는 연산이 dict 를 사용하는 것보다 대부분 느리다. 
  4. . 연산자의 사용을 피하라
    1. x.name을 입력하면 변수x -> x의 name속성이 있는지를 찾는다. 따라서 메서드 검색이나 모듈검색이 잦은 경우에는 지역변수를 사용해 속성검색연산을 먼저 제거하는것이 좋다. 
    2. 성능이 중요한 곳에서는 유용하게 사용할수 있을거 같다.

      def test_foo(self):
          first = timeit('math.sqrt(2.0)','import math')
          print(first)
          ## 0.0720708370209
       
          second = timeit('sqrt(2.0)','from math import sqrt')
          print(second)
          ## 0.0479161739349
  5. 흔하지 않은 경우를 처리하기 위해서는 예외를 사용하라.
    1. 에러가 잘 발생하지 않는 경우, 에러를 피하려고 아래와 같이 추가 검사를 수행하는 경우가 있고 vs 예외를 잡는 방식으로 에러를 처리 할수도 있는데, 성능측면에서 if보다는 예외로 처리 하는 것이 더 빠르다.
    2. 추가 검사를 수행하는 경우가 있고 vs 예외를 잡는 방식으로 에러

      def test_user(self):
          '''
          보통은 User객체가 있다는 가정
          user = User("a""a"10"a")
          '''
          user = None
       
          start_t = time.time()
          friend_id = self._get_friend_id_if(user)
          end_t = time.time()
          print(end_t-start_t)
          #9.53674316406e-07
       
          start_t2 = time.time()
          friend_id = self._get_friend_id_try(user)
          end_t2 = time.time()
          print(end_t2-start_t2)
          #3.09944152832e-06
       
      def _get_friend_id_if(self, user):
          if user:
              return user.init_id+123
          else:
              return 0
       
      def _get_friend_id_try(self, user):
          try:
              return user.init_id+123
          except:
              return 0
  6. 흔한 경우에 대한 예외처리를 피하라
    1. 흔하게 발생하는 경우에 대해서는 예외처리 코드 작성을 피하라. 
    2. 예를 들어 dict 검색에 있어, 대부분 키가 존재 하지 않는다고 가정하면, 
    3. key를 찾을수 없는 경우 in으로 키값이 존재하는지를 확인하고, 검색을 수행하는게 더 효율적이다. 

      def test_dict_key(self):
          tmp_dict = {"first_name":"a",
                      "last_name":"a",
                      "age1":10,
                      "age2":10,
                      "age3":10,
                      "age4":10,
                      "addr":"blabla"}
          #first
          self._used_if_check(tmp_dict,"not_key")
       
          #second
          self._used_try(tmp_dict,"not_key")
       
      def _used_try(self, items, k):
          start_t=time.time()
          try:
              v = items[k]
          except KeyError:
              v = None
          end_t=time.time()
          print("try except", end_t-start_t)
          return v
       
      def _used_if_check(self, items, k):
          start_t=time.time()
          if k in items:
              v = items[k]
          else:
              v = None
          end_t=time.time()
          print("in ", end_t-start_t)
          return v
    4. (second 가 검색을 수행하고 예외를 잡는거고, first 는 키값이 존재하는지를 확인하고 검색을 수행하기때문에 더 빠를거 같긴 한데.. print로 시간을 찍어보면 in으로 키값이 존재하는지를 체크하는 수행시간이 들쭉날쭉..ㅠ)

  7. 데코레이터와 메타클래스를 사용하라.