Python & waktu dan pengoptimalan memori

pengantar

Seringkali kecepatan eksekusi python buruk. Beberapa orang menolak untuk menggunakan python karena alasan ini, tetapi ada beberapa cara untuk mengoptimalkan kode python untuk waktu dan penggunaan memori. 





Saya ingin membagikan beberapa metode yang membantu dalam masalah kehidupan nyata. Saya menggunakan win10 x64.





Hemat memori dengan Python

Mari kita ambil contoh yang sangat nyata sebagai contoh. Misalkan kita memiliki beberapa toko yang didalamnya terdapat daftar barang. Jadi kami perlu bekerja dengan barang-barang ini. Pilihan terbaik adalah ketika semua barang disimpan di database, tetapi tiba-tiba terjadi kesalahan, dan kami memutuskan untuk membongkar semua barang ke dalam memori untuk memprosesnya. Dan kemudian muncul pertanyaan yang masuk akal: akankah kita memiliki cukup memori untuk bekerja dengan begitu banyak barang?





Mari pertama-tama buat kelas yang bertanggung jawab atas toko kita. Ini hanya akan memiliki 2 kolom: name dan listGoods, yang masing-masing bertanggung jawab atas nama toko dan daftar produk.





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



Sekarang kami ingin mengisi toko dengan barang (yaitu, isi kolom listGoods). Untuk melakukan ini, kita akan membuat kelas yang bertanggung jawab atas informasi tentang satu produk (saya menggunakan kelas data untuk contoh seperti itu).





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





Sebelum melanjutkan dengan pilihan fungsionalitas untuk mengoptimalkan kode, perlu dilakukan pengoptimalan internal kode dalam python murni, untuk menghilangkan loop dalam loop dalam satu loop secara maksimal, bersihkan memori dengan tangan Anda dan hapus elemen yang tidak perlu selama eksekusi kode. Jangan berharap bahwa menulis ulang kode Anda ke bahasa lain akan menyelesaikan semua masalah Anda, belajar mencari hambatan dalam kode dan mengoptimalkannya secara algoritme atau menggunakan trik bahasa itu sendiri.








All Articles