Python et optimisation du temps et de la mémoire

introduction

Souvent, la vitesse d'exécution de python est médiocre. Certaines personnes refusent d'utiliser python pour cette raison même, mais il existe plusieurs façons d'optimiser le code python à la fois pour l'utilisation du temps et de la mémoire. 





Je voudrais partager plusieurs méthodes qui aident dans les problèmes de la vie réelle. J'utilise win10 x64.





Économisez de la mémoire avec Python

Prenons un exemple très réel à titre d'exemple. Supposons que nous ayons un magasin dans lequel il y a une liste de produits. Nous devions donc travailler avec ces produits. La meilleure option est lorsque toutes les marchandises sont stockées dans la base de données, mais tout à coup quelque chose s'est mal passé, et nous avons décidé de décharger toutes les marchandises en mémoire afin de les traiter. Et puis une question raisonnable se pose: aurons-nous assez de mémoire pour travailler avec autant de produits?





Créons d'abord une classe responsable de notre boutique. Il n'aura que 2 champs: name et listGoods, qui sont respectivement responsables du nom du magasin et de la liste des produits.





class ShopClass:
    def __init__(self, name=""):
        self.name = name
        self.listGoods = []
      
      



Maintenant, nous voulons remplir le magasin de marchandises (à savoir, remplir le champ listGoods). Pour ce faire, nous allons créer une classe responsable des informations sur un produit (j'utilise dataclass pour de tels exemples).





#    dataclass,   
# pip install dataclasses
#     
# from dataclasses import dataclass 
@dataclass
class DataGoods:
    name:str
    price:int
    unit:str
      
      



. 200 3 :





shop = ShopClass("MyShop")
for _ in range(200):
    shop.listGoods.extend([
        DataGoods("", 20000, "RUB"),
        DataGoods("", 45000, "RUB"),
        DataGoods("", 2000, "RUB")
    ])
      
      



, ( pympler):





from pympler import asizeof
print(" :", asizeof.asizeof(shop))
>>>  : 106648
      
      



, 106. , , , 600 , , , . , , , , , , . ( , ).





. Python , , . , python __dict__ , . , .





shop = ShopClass("MyShop")
print(shop.__dict__)  
>>> {'name': 'MyShop', 'listGoods': []}

shop.city = ""
print(shop.__dict__) 
>>> {'name': 'MyShop', 'listGoods': [], 'city': ''}
      
      



. , . python’e __slots__, __dict__. __dict__ , , . :





class ShopClass:
    __slots__ = ("name", "listGoods")
    def __init__(self, name=""):
        self.name = name
        self.listGoods = []
@dataclass
class DataGoods:
    __slots__ = ("name", "price", "unit")
    name:str
    price:int
    unit:str
      
      



.





from pympler import asizeof
print(" :", asizeof.asizeof(shop))
>>>  : 43904
      
      



, , , 2.4 ( ,  Python, ). , . , , , :





shop = ShopClass("MyShop")
shop.city = ""
>>> AttributeError: 'ShopClass' object has no attribute 'city'
      
      



, - , __dict__ ptyhon' , . timeit, __slots__ (__dict__):





import timeit
code = """
class ShopClass:
    #__slots__ = ("name", "listGoods")
    def __init__(self, name=""):
        self.name = name
        self.listGoods = []
@dataclass
class DataGoods:
    #__slots__ = ("name", "price", "unit")
    name:str
    price:int
    unit:str
shop = ShopClass("MyShop")
for _ in range(200):
    shop.listGoods.extend([
        DataGoods("", 20000, "RUB"),
        DataGoods("", 45000, "RUB"),
        DataGoods("", 2000, "RUB")
])
"""
print(timeit.timeit(code, number=60000))
>>> 33.4812513
      
      



__slots__ (#__slots__ = ("name", "price", "unit") -> __slots__ = ("name", "price", "unit") # __slots__ = ("name", "listGoods") -> __slots__ = ("name", "listGoods")):





#  __slots__   
print(timeit.timeit(code, number=60000))
>>> 28.535005599999998
      
      



, 15% ( , ).





, , , .





python , (, ), C/C++ .





, .





Cython

Cython , Python, . , Python , ( 20.000.000 ):





import time
class ShopClass:
   __slots__ = ("name", "listGoods")
   def __init__(self, name=""):
      self.name = name
      self.listGoods = []
@dataclass
class DataGoods:
   __slots__ = ("name", "price", "unit")
   name: str
   price: int
   unit: str
shop = ShopClass("MyShop")
t = time.time()
for _ in range(200*100000):
   shop.listGoods.extend([
      DataGoods("", 20000, "RUB"),
      DataGoods("", 45000, "RUB"),
      DataGoods("", 2000, "RUB")
   ])
print("   PYTHON:", time.time()-t)
>>>    PYTHON: 44.49887752532959
telephoneSum, televizorSum, tosterSum = 0, 0, 0
t = time.time()
for goods in shop.listGoods:
   if goods.name == "":
      telephoneSum += goods.price
   elif goods.name == "":
      televizorSum += goods.price
   elif goods.name == "":
      tosterSum += goods.price
print("    PYTHON:", time.time() - t)
>>>     PYTHON: 13.135360717773438
      
      



, . cython. cython_npm (. ): pip install cython-npm. , cython_code cython_data.pyx ( cython .pyx).





cython:





cdef class CythonShopClass:
   cdef str name
   cdef list listGoods

   def __init__(self, str name):
       self.name = name
       self.listGoods = []
      
      



cython , ( , , ). cdef < > < > . cython. my_def() cdef, def, python . .pyx (# cython: language_level=3).





# cython: language_level=3
#      
cdef class CythonDataGoods:
   cdef str name
   cdef int price
   cdef str unit
   def __init__(self, str name, int price, str unit):
       self.name = name
       self.price = price
       self.unit = unit
cdef int c_testFunc():
    cdef CythonShopClass shop
    cdef CythonDataGoods goods
    cdef int i, t, telephoneSum, televizorSum, tosterSum
    size, i, telephoneSum, televizorSum, tosterSum = 0, 0, 0, 0, 0
    shop = CythonShopClass("MyShop")
    t = time.time()
    for i in range(200*100000):
       shop.listGoods.extend([
           CythonDataGoods("", 20000, "RUB"),
           CythonDataGoods("", 45000, "RUB"),
           CythonDataGoods("", 2000, "RUB")
       ])
    print("   CYTHON:", time.time()-t)
    t = time.time()
    for goods in shop.listGoods:
        if goods.name == "":
            telephoneSum += goods.price
        elif goods.name == "":
            televizorSum += goods.price
        elif goods.name == "":
            tosterSum += goods.price
    print("    CYTHON:", time.time() - t)
    return 0
def my_def():
    data = c_testFunc()
    return data
      
      



main.py cython . :





from cython_npm.cythoncompile import export
from cython_npm.cythoncompile import install
import time
      
      



cython python





export('cython_code/cython_data.pyx')
import cython_code.cython_data as cython_data
      
      



cython





if __name__ == "__main__":
   a = cython_data.my_def()
      
      



. , . cython, , :





>>>    CYTHON: 4.082242012023926
      
      



:





>>>     CYTHON: 1.0513946056365967
      
      



, 44 4 , 11 . 13 1 , 13 .





, cython - , , , . , , cython 100 .





Python

, - , . , , . , , . :





shop = ShopClass("MyShop")
t = time.time()
getGoods = lambda index: {0: ("", 20000, "RUB"), 
                          1: ("", 45000, "RUB"), 
                          2:("", 2000, "RUB")}.get(index) 
shop.listGoods = [DataGoods(*getGoods(i%3)) for i in range(200*100000)]
print("   PYTHON:", time.time()-t)
>>>     PYTHON: 19.719463109970093
      
      



2 , python. python - , , .





PyPy

, cython , ( ), . , . PyPy, python, JIT . PyPy , , . python PyPy . 





PyPy . , cmd , pypy3.exe, . cmd :





, 19 python’ 4.5 , 4 .





. , , python , .





. Numba, NumPy, Nim multiprocessing. , . , python .





Avant de procéder au choix de la fonctionnalité d'optimisation du code, il est nécessaire de procéder à une optimisation interne du code en pur python, de se débarrasser des boucles en boucles en boucles en boucle au maximum, de nettoyer la mémoire avec vos mains et supprimer les éléments inutiles lors de l'exécution du code. Ne vous attendez pas à ce que la réécriture de votre code dans un autre langage résoudra tous vos problèmes, apprenez à rechercher les goulots d'étranglement dans le code et à les optimiser de manière algorithmique ou en utilisant des astuces du langage lui-même.








All Articles