Python & Zeit- und Speicheroptimierung

Einführung

Oft ist die Ausführungsgeschwindigkeit von Python schlecht. Einige Leute lehnen die Verwendung von Python aus diesem Grund ab, aber es gibt verschiedene Möglichkeiten, Python-Code sowohl für die Zeit- als auch für die Speichernutzung zu optimieren. 





Ich möchte einige Methoden vorstellen, die bei Problemen im wirklichen Leben helfen. Ich benutze Win10 x64.





Speichern Sie Speicher mit Python

Nehmen wir als Beispiel ein sehr reales Beispiel. Angenommen, wir haben ein Geschäft, in dem es eine Warenliste gibt. Also mussten wir mit diesen Waren arbeiten. Die beste Option ist, wenn alle Waren in der Datenbank gespeichert sind, aber plötzlich etwas schief gelaufen ist und wir beschlossen, alle Waren in den Speicher zu entladen, um sie zu verarbeiten. Und dann stellt sich eine vernünftige Frage: Werden wir genug Gedächtnis haben, um mit so vielen Gütern zu arbeiten?





Erstellen wir zunächst eine Klasse, die für unser Geschäft verantwortlich ist. Es werden nur 2 Felder angezeigt: name und listGoods, die für den Namen des Geschäfts bzw. die Liste der Produkte verantwortlich sind.





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



Jetzt wollen wir den Laden mit Waren füllen (nämlich das Feld listGoods ausfüllen). Zu diesem Zweck erstellen wir eine Klasse, die für Informationen zu einem Produkt verantwortlich ist (für solche Beispiele verwende ich eine Datenklasse).





#    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 .





Bevor Sie mit der Auswahl der Funktionen zur Optimierung des Codes fortfahren, müssen Sie eine interne Optimierung des Codes in reinem Python durchführen, um Schleifen in Schleifen in Schleifen in einer Schleife maximal zu entfernen, den Speicher mit Ihren Händen und zu bereinigen Entfernen Sie unnötige Elemente während der Codeausführung. Erwarten Sie nicht, dass das Umschreiben Ihres Codes in eine andere Sprache alle Ihre Probleme löst. Lernen Sie, nach Engpässen im Code zu suchen und diese algorithmisch oder mithilfe von Tricks der Sprache selbst zu optimieren.








All Articles