Cara menggunakan cProfile untuk profil kod Python

Python mungkin bukan bahasa terpantas, tetapi seringkali cukup pantas. Dan Python sangat sesuai apabila masa pengaturcara lebih penting daripada masa CPU.

Yang mengatakan, jika aplikasi Python yang diberikan lambat, anda tidak wajib menghisapnya. Alat yang disertakan dengan pemasangan stok jurubahasa Python dapat memberi anda maklum balas terperinci mengenai bahagian mana dari program anda yang lambat, dan menawarkan beberapa petunjuk mengenai cara mempercepatnya.

Cara menggunakan cProfile

The cProfilemodul mengumpulkan statistik tentang masa pelaksanaan program Python. Ia boleh melaporkan apa sahaja dari keseluruhan aplikasi ke satu pernyataan atau ungkapan.

Berikut adalah contoh mainan cara menggunakan cProfile:

def add (x, y): x + = str (y) return x def add_2 (x, y): if y% 20000 == 0: z = [] untuk q dalam julat (0,400000): z.lampirkan ( q) def utama (): a = [] untuk n dalam julat (0,200000): tambah (a, n) add_2 (a, n) jika __name__ == '__main__': import cProfile cProfile.run ('main ( ) ') 

Contoh ini menjalankan main()fungsi aplikasi dan menganalisis prestasi main()dan semua main()panggilan. Anda juga boleh menganalisis hanya  sebahagian daripada program, tetapi penggunaan yang paling biasa untuk pemula adalah membuat profil keseluruhan program.

Jalankan contoh di atas dan anda akan disambut dengan output seperti berikut:

Apa yang ditunjukkan di sini adalah senarai semua panggilan fungsi yang dibuat oleh program, bersama dengan statistik mengenai masing-masing:

  • Di bahagian atas (baris pertama berwarna biru), kita melihat jumlah panggilan yang dibuat dalam program berprofil dan jumlah masa pelaksanaan. Anda juga mungkin melihat angka untuk "panggilan primitif," yang bermaksud panggilan bukan rekursif , atau panggilan yang dibuat terus ke fungsi yang pada gilirannya tidak memanggil diri mereka lebih jauh ke dalam timbunan panggilan.
  • ncalls : Bilangan panggilan yang dibuat. Sekiranya anda melihat dua nombor dipisahkan dengan garis miring, nombor kedua adalah jumlah panggilan primitif untuk fungsi tersebut.
  • tottime : Jumlah masa yang dihabiskan dalam fungsi, tidak termasuk panggilan ke fungsi lain.
  • percall : Waktu purata setiap panggilan untuk tottime , diperoleh dengan mengambil tottime dan membahagikannya dengan panggilan .
  • cumtime : Jumlah masa yang dihabiskan dalam fungsi, termasuk panggilan ke fungsi lain.
  • percall (# 2): Rata-rata masa bagi setiap panggilan untuk cumtime ( cumtime dibahagi dengan ncalls ).
  • nama fail: lineno : Nama fail, nombor baris, dan nama fungsi untuk panggilan yang dimaksudkan.

Cara mengubah laporan cProfile

Secara lalai, cProfilemenyusun outputnya dengan "nama standard," yang bermaksud bahawa ia disusun mengikut teks di lajur paling kanan (nama fail, nombor baris, dll.).

Format lalai berguna jika anda mahukan laporan umum dari atas ke bawah setiap panggilan fungsi untuk rujukan. Tetapi jika anda cuba sampai ke tahap yang paling rendah, anda mungkin mahu bahagian program yang paling memakan masa disenaraikan terlebih dahulu.

Kami dapat menghasilkan hasil ini dengan menggunakan  cProfile sedikit berbeza. Perhatikan bagaimana bahagian bawah program di atas dapat disusun semula untuk menyusun statistik mengikut lajur yang berbeza (dalam kes ini ncalls):

jika __name__ == '__main__': import cProfile, pstats profiler = cProfile.Profile () profiler.enable () main () profiler.disable () stats = pstats.Stats (profiler) .sort_stats ('ncalls') stats.print_stats () 

Hasilnya akan kelihatan seperti ini:

Inilah cara semua ini berfungsi:

  • Bukannya melaksanakan arahan dengan cara cProfile.run(), yang tidak adalah sangat fleksibel, kami akan membuat profil objek , profiler.
  • Apabila kita ingin memprofilkan beberapa tindakan, pertama-tama kita memanggil .enable()contoh objek profiler, kemudian menjalankan tindakan, kemudian memanggil .disable(). (Ini adalah salah satu cara untuk memprofilkan hanya sebahagian daripada program.)
  • The pstatsmodul digunakan untuk memanipulasi hasil yang dikutip oleh objek profiler dan mencetak hasil tersebut.

Menggabungkan objek profiler dan pstatsmembolehkan kita memanipulasi data profil yang diambil - misalnya, untuk menyusun statistik yang dihasilkan secara berbeza. Dalam contoh ini, menggunakan .sort_stats('ncalls')menyusun statistik mengikut ncallslajur. Pilihan jenis lain ada.

Cara menggunakan hasil cProfile untuk pengoptimuman

Pilihan jenis yang tersedia untuk cProfile output membolehkan kita mengatasi masalah prestasi yang berpotensi dalam program.

ncalls

Maklumat pertama dan paling penting yang dapat anda ketahui cProfileialah fungsi mana yang paling kerap dipanggil, melalui ncallslajur.

Di Python, tindakan membuat panggilan fungsi hanya mengeluarkan sejumlah besar overhead. Sekiranya beberapa fungsi dipanggil berulang kali dalam gelung ketat, walaupun itu bukan fungsi jangka panjang, itu dijamin mempengaruhi prestasi.

Dalam contoh di atas, fungsi add(dan fungsi add_2) disebut berulang kali dalam satu gelung. Memindahkan gelung ke addfungsi itu sendiri, atau menyisipkan addfungsi sepenuhnya, akan menyelesaikan masalah ini.

tottime

Perincian statistik lain yang berguna yang berfungsi menghabiskan sebahagian besar waktunya untuk dilaksanakan, melalui tottimelajur.

Dalam contoh di atas, add_2fungsi menggunakan gelung untuk mensimulasikan beberapa pengiraan yang mahal, yang mendorong tottimeskornya ke puncak. Apa-apa fungsi dengan tottimeskor tinggi wajar dilihat dari dekat, terutama jika disebut berkali-kali atau dalam gelung ketat.

Perhatikan bahawa anda selalu perlu mempertimbangkan konteks  di mana fungsi tersebut digunakan. Sekiranya fungsi mempunyai tinggi tottimetetapi hanya dipanggil sekali - sebagai contoh, hanya ketika program dimulakan - kemungkinan besar akan menjadi hambatan. Walau bagaimanapun, jika anda cuba mengurangkan masa permulaan, anda pasti ingin tahu sama ada fungsi yang dipanggil semasa memulakan membuat semua yang lain menunggu.

Cara mengeksport data cProfile

Sekiranya anda ingin menggunakan cProfilestatistik yang dihasilkan dengan cara yang lebih maju, anda boleh mengeksportnya ke fail data:

stats = pstats.Stats (profiler) stats.dump_stats ('/ path / to / stats_file.dat') 

Fail ini dapat dibaca kembali dengan menggunakan pstatsmodul, kemudian disusun atau dipaparkan dengan pstats. Data juga dapat digunakan kembali oleh program lain. Dua contoh:

  • pyprof2calltreememberikan visualisasi terperinci mengenai grafik panggilan program dan statistik penggunaan dari data profil. Artikel ini memberikan contoh penggunaan dunia nyata yang terperinci.
  • snakevizjuga menghasilkan visualisasi dari cProfiledata, tetapi menggunakan representasi yang berbeda untuk data - "sunburst" dan bukan grafik "api" pyprof2calltree

Di luar cProfile untuk profil Python

cProfilebukan satu-satunya cara untuk profil aplikasi Python. cProfiletentunya adalah salah satu cara yang paling mudah, memandangkan ia digabungkan dengan Python. Tetapi yang lain patut mendapat perhatian.

Satu projek, py-spymembina profil untuk aplikasi Python dengan mengambil sampel aktiviti panggilannya. py-spydapat digunakan untuk memeriksa aplikasi Python yang sedang berjalan tanpa harus menghentikan dan menghidupkannya kembali, dan tanpa harus mengubah pangkalan kode, sehingga dapat digunakan untuk profil aplikasi yang digunakan. py-spyjuga menghasilkan beberapa statistik mengenai overhead yang ditanggung oleh runtime Python (misalnya, overhead pengumpulan sampah), yang cProfiletidak.