Cara Mengoptimalkan Skrip Python Anda untuk Performa Lebih Baik

Cara Mengoptimalkan Skrip Python Anda Untuk Performa Lebih Baik



Mengoptimalkan skrip Python untuk kinerja yang lebih baik melibatkan identifikasi dan mengatasi hambatan dalam kode kita, membuatnya berjalan lebih cepat dan efisien. Python adalah bahasa pemrograman populer dan kuat yang digunakan dalam berbagai aplikasi saat ini termasuk analisis data, proyek ML (pembelajaran mesin), pengembangan web, dan banyak lagi. Pengoptimalan kode Python adalah strategi untuk meningkatkan kecepatan dan efisiensi program pengembang saat melakukan aktivitas apa pun menggunakan lebih sedikit baris kode, lebih sedikit memori, atau sumber daya tambahan. Kode yang besar dan tidak efisien dapat memperlambat program yang dapat mengakibatkan buruknya kepuasan klien dan potensi kerugian finansial, atau perlunya lebih banyak pekerjaan untuk memperbaiki dan memecahkan masalah.

Hal ini diperlukan saat melakukan tugas yang memerlukan pemrosesan beberapa tindakan atau data. Oleh karena itu, mengganti dan meningkatkan beberapa blok kode dan fungsi yang tidak efektif dapat memberikan hasil yang luar biasa seperti berikut:

  1. Tingkatkan kinerja aplikasi
  2. Buat kode yang mudah dibaca dan terorganisir
  3. Jadikan pemantauan kesalahan dan proses debug lebih sederhana
  4. Menghemat daya komputasi yang cukup besar dan lain sebagainya

Profil Kode Anda

Sebelum kita mulai melakukan pengoptimalan, penting untuk mengidentifikasi bagian kode proyek yang memperlambatnya. Teknik pembuatan profil dengan Python mencakup paket cProfile dan profile. Manfaatkan alat tersebut untuk mengukur seberapa cepat fungsi dan baris kode tertentu dijalankan. Modul cProfile menghasilkan laporan yang merinci berapa lama setiap fungsi skrip dijalankan. Laporan ini dapat membantu kami menemukan fungsi apa pun yang berjalan lambat sehingga kami dapat memperbaikinya.







Cuplikan Kode:



impor cProfil sebagai cP
def hitungJumlah ( inputNumber ) :
jumlah_of_input_numbers = 0
ketika inputNumber > 0 :
jumlah_of_input_angka + = inputNumber % 10
    inputNumber // = 10
mencetak ( 'Jumlah Semua Digit pada Nomor Masukan adalah: 'jumlah_of_input_numbers'' )
kembali jumlah_of_input_numbers
def main_func ( ) :
cP. berlari ( 'hitungJumlah(9876543789)' )
jika __nama__ == '__utama__' :
main_func ( )

Program ini membuat total lima pemanggilan fungsi seperti yang terlihat pada baris pertama keluaran. Detail setiap pemanggilan fungsi ditampilkan dalam beberapa baris berikut termasuk berapa kali fungsi tersebut dipanggil, keseluruhan durasi waktu dalam fungsi, durasi waktu per panggilan, dan jumlah keseluruhan waktu dalam fungsi (termasuk semua fungsi yang dipanggil).



Selain itu, program mencetak laporan pada layar prompt yang menunjukkan bahwa program menyelesaikan waktu eksekusi semua tugasnya dalam 0,000 detik. Ini menunjukkan seberapa cepat program ini.





Pilih Struktur Data yang Tepat

Karakteristik kinerja bergantung pada struktur data. Secara khusus, kamus lebih cepat untuk pencarian daripada daftar mengenai penyimpanan tujuan umum. Pilih struktur data yang paling sesuai untuk operasi yang akan kami lakukan pada data Anda jika Anda mengetahuinya. Contoh berikut menyelidiki efektivitas struktur data yang berbeda untuk proses yang identik guna menentukan apakah ada elemen dalam struktur data.



Kami mengevaluasi waktu yang diperlukan untuk memeriksa apakah suatu elemen ada di setiap struktur data—daftar, kumpulan, dan kamus—dan membandingkannya.

OptimalkanDataType.py:

impor Waktui sebagai tt
impor acak sebagai rndobj
# Hasilkan daftar bilangan bulat
daftar_data_acak = [ rndobj. randint ( 1 , 10.000 ) untuk _ di dalam jangkauan ( 10.000 ) ]
# Buat satu set dari data yang sama
kumpulan data_acak = mengatur ( daftar_data_acak )

# Buat kamus dengan data yang sama dengan kunci
obj_DataDictionary = { pada satu: Tidak ada untuk pada satu di dalam daftar_data_acak }

# Elemen yang akan dicari (ada di data)
nomor_acak_untuk_ditemukan = rndobj. pilihan ( daftar_data_acak )

# Ukur waktu untuk memeriksa keanggotaan dalam daftar
daftar_waktu = tt. Waktui ( lambda : nomor_acak_ke_temukan di dalam daftar_data_acak , nomor = 1000 )

# Ukur waktu untuk memeriksa keanggotaan dalam satu set
Atur waktu = tt. Waktui ( lambda : nomor_acak_ke_temukan di dalam kumpulan data_acak , nomor = 1000 )

# Ukur waktu untuk memeriksa keanggotaan dalam kamus
dict_time = tt. Waktui ( lambda : nomor_acak_ke_temukan di dalam obj_DataDictionary , nomor = 1000 )

mencetak ( F 'Daftar waktu pemeriksaan keanggotaan: {list_time:.6f} detik' )
mencetak ( F 'Tetapkan waktu pemeriksaan keanggotaan: {set_time:.6f} detik' )
mencetak ( F 'Waktu pemeriksaan keanggotaan kamus: {dict_time:.6f} detik' )

Kode ini membandingkan performa daftar, kumpulan, dan kamus saat melakukan pemeriksaan keanggotaan. Secara umum, set dan kamus jauh lebih cepat daripada daftar untuk pengujian keanggotaan karena menggunakan pencarian berbasis hash, sehingga memiliki kompleksitas waktu rata-rata O(1). Daftar, di sisi lain, harus melakukan pencarian linier yang menghasilkan pengujian keanggotaan dengan kompleksitas waktu O(n).

  Cuplikan layar deskripsi komputer dibuat secara otomatis

Gunakan Fungsi Bawaan, Bukan Loop

Banyak fungsi atau metode bawaan di Python yang dapat digunakan untuk melakukan tugas-tugas umum seperti pemfilteran, pengurutan, dan pemetaan. Menggunakan rutinitas ini daripada membuat perulangan membantu mempercepat kode karena sering kali kinerjanya dioptimalkan.

Mari buat beberapa kode contoh untuk membandingkan kinerja pembuatan loop khusus dengan memanfaatkan fungsi bawaan untuk pekerjaan umum (seperti map(), filter(), dan sortir()). Kami akan mengevaluasi seberapa baik kinerja berbagai metode pemetaan, penyaringan, dan penyortiran.

Fungsi Bawaan.py:

impor Waktui sebagai tt
# Contoh daftar angka_daftar
nomor_daftar = daftar ( jangkauan ( 1 , 10.000 ) )

# Berfungsi untuk mengkuadratkan angka_daftar menggunakan loop
def persegi_menggunakan_loop ( nomor_daftar ) :
hasil_persegi = [ ]
untuk pada satu di dalam nomor_daftar:
hasil_persegi. menambahkan ( pada satu ** 2 )
kembali hasil_persegi
# Berfungsi untuk memfilter daftar_bilangan genap menggunakan loop
def filter_even_using_loop ( nomor_daftar ) :
filter_hasil = [ ]
untuk pada satu di dalam nomor_daftar:
jika pada satu% 2 == 0 :
filter_hasil. menambahkan ( pada satu )
kembali filter_hasil
# Berfungsi untuk mengurutkan angka_daftar menggunakan loop
def sort_using_loop ( nomor_daftar ) :
kembali diurutkan ( nomor_daftar )
# Ukur waktu untuk mengkuadratkan angka_daftar menggunakan peta()
peta_waktu = tt. Waktui ( lambda : daftar ( peta ( lambda x: x** 2 , nomor_daftar ) ) , nomor = 1000 )
# Ukur waktu untuk memfilter daftar_bilangan genap menggunakan filter()
filter_waktu = tt. Waktui ( lambda : daftar ( Saring ( lambda x: x% 2 == 0 , nomor_daftar ) ) , nomor = 1000 )
# Ukur waktu untuk mengurutkan angka_daftar menggunakan diurutkan()
diurutkan_waktu = tt. Waktui ( lambda : diurutkan ( nomor_daftar ) , nomor = 1000 )
# Ukur waktu untuk mengkuadratkan angka_daftar menggunakan loop
loop_map_time = tt. Waktui ( lambda : persegi_menggunakan_loop ( nomor_daftar ) , nomor = 1000 )
# Ukur waktu untuk memfilter daftar_bilangan genap menggunakan loop
loop_filter_time = tt. Waktui ( lambda : filter_even_using_loop ( nomor_daftar ) , nomor = 1000 )
# Ukur waktu untuk mengurutkan angka_daftar menggunakan loop
loop_sorted_time = tt. Waktui ( lambda : sort_using_loop ( nomor_daftar ) , nomor = 1000 )
mencetak ( 'Daftar Nomor berisi 10.000 elemen' )
mencetak ( F 'Peta() Waktu: {map_time:.6f} detik' )
mencetak ( F 'Filter() Waktu: {filter_time:.6f} detik' )
mencetak ( F 'Diurutkan() Waktu: {sorted_time:.6f} detik' )
mencetak ( F 'Waktu Loop (Peta): {loop_map_time:.6f} detik' )
mencetak ( F 'Waktu Perulangan (Filter): {loop_filter_time:.6f} detik' )
mencetak ( F 'Waktu Perulangan (Diurutkan): {loop_sorted_time:.6f} detik' )

Kita mungkin akan mengamati bahwa fungsi bawaan (map(), filter(), dan sortir()) lebih cepat daripada loop khusus untuk tugas-tugas umum ini. Fungsi bawaan di Python menawarkan pendekatan yang lebih ringkas dan mudah dipahami untuk melaksanakan tugas-tugas ini dan sangat dioptimalkan untuk kinerja.

Optimalkan Loop

Jika penulisan loop diperlukan, ada beberapa teknik yang dapat kita lakukan untuk mempercepatnya. Secara umum, loop range() lebih cepat daripada melakukan iterasi mundur. Hal ini karena range() menghasilkan iterator tanpa membalik daftar yang dapat menjadi operasi mahal untuk daftar yang panjang. Selain itu, karena range() tidak membuat daftar baru di memori, ia menggunakan lebih sedikit memori.

OptimalkanLoop.py:

impor Waktui sebagai tt
# Contoh daftar angka_daftar
nomor_daftar = daftar ( jangkauan ( 1 , 100.000 ) )
# Berfungsi untuk mengulangi daftar dalam urutan terbalik
def loop_reverse_iteration ( ) :
hasil_terbalik = [ ]
untuk J di dalam jangkauan ( hanya ( nomor_daftar ) - 1 , - 1 , - 1 ) :
hasil_terbalik. menambahkan ( nomor_daftar [ J ] )
kembali hasil_terbalik
# Berfungsi untuk mengulangi daftar menggunakan range()
def loop_range_iteration ( ) :
rentang_hasil = [ ]
untuk k di dalam jangkauan ( hanya ( nomor_daftar ) ) :
rentang_hasil. menambahkan ( nomor_daftar [ k ] )
kembali rentang_hasil
# Ukur waktu yang diperlukan untuk melakukan iterasi terbalik
waktu_mundur = tt. Waktui ( loop_reverse_iteration , nomor = 1000 )
# Ukur waktu yang diperlukan untuk melakukan iterasi rentang
rentang_waktu = tt. Waktui ( loop_range_iteration , nomor = 1000 )
mencetak ( 'Daftar nomor berisi 100.000 catatan' )
mencetak ( F 'Waktu Iterasi Terbalik: {reverse_time:.6f} detik' )
mencetak ( F 'Rentang Waktu Iterasi: {range_time:.6f} detik' )

Hindari Panggilan Fungsi yang Tidak Perlu

Ada beberapa overhead setiap kali suatu fungsi dipanggil. Kode berjalan lebih cepat jika pemanggilan fungsi yang tidak perlu dihindari. Misalnya, daripada menjalankan fungsi penghitungan nilai berulang kali, cobalah menyimpan hasil penghitungan dalam variabel dan menggunakannya.

Alat untuk Membuat Profil

Untuk mempelajari lebih lanjut tentang kinerja kode Anda, selain pembuatan profil bawaan, kami dapat memanfaatkan paket pembuatan profil eksternal seperti cProfile, Pyflame, atau SnakeViz.

Hasil Tembolok

Jika kode kita perlu melakukan perhitungan yang mahal, kita mungkin mempertimbangkan untuk menyimpan hasilnya dalam cache untuk menghemat waktu.

Pemfaktoran Ulang Kode

Memfaktorkan ulang kode agar lebih mudah dibaca dan dipelihara terkadang merupakan bagian penting dalam pengoptimalannya. Program yang lebih cepat mungkin juga lebih bersih.

Gunakan Kompilasi Just-in-Time (JIT)

Perpustakaan seperti PyPy atau Numba dapat menyediakan kompilasi JIT yang secara signifikan dapat mempercepat jenis kode Python tertentu.

Tingkatkan Python

Pastikan Anda menggunakan Python versi terbaru karena versi yang lebih baru sering kali menyertakan peningkatan kinerja.

Paralelisme dan Konkurensi

Untuk proses yang dapat diparalelkan, selidiki teknik paralel dan sinkronisasi seperti multiprosesing, threading, atau asyncio.

Ingatlah bahwa benchmarking dan pembuatan profil harus menjadi pendorong utama pengoptimalan. Berkonsentrasilah pada peningkatan area kode kami yang memiliki pengaruh paling signifikan terhadap kinerja, dan terus uji peningkatan Anda untuk memastikan bahwa peningkatan tersebut memiliki efek yang diinginkan tanpa menimbulkan lebih banyak cacat.

Kesimpulan

Kesimpulannya, pengoptimalan kode Python sangat penting untuk meningkatkan kinerja dan efektivitas sumber daya. Pengembang dapat meningkatkan kecepatan eksekusi dan daya tanggap aplikasi Python mereka secara signifikan menggunakan berbagai teknik seperti memilih struktur data yang sesuai, memanfaatkan fungsi bawaan, mengurangi loop tambahan, dan mengelola memori secara efektif. Pembandingan dan pembuatan profil yang berkelanjutan harus mengarahkan upaya pengoptimalan, memastikan bahwa kemajuan kode sesuai dengan persyaratan kinerja dunia nyata. Untuk menjamin keberhasilan proyek jangka panjang dan mengurangi kemungkinan timbulnya masalah baru, pengoptimalan kode harus selalu diimbangi dengan tujuan keterbacaan dan pemeliharaan kode.