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.