5 Peningkatan kecepatan di Python 3.7

Berikut adalah 5 peningkatan kecepatan di Python 3.7. Peringatan : beberapa topik dalam artikel ini cukup terperinci dan di luar tingkat yang biasanya saya tulis di blog.

  1. Memanggil metode yang lebih cepat (mungkin)

Ada banyak cara untuk mengubah CPython, baik dengan memodifikasi eksekusi dari Opcode atau dengan menambahkan Opcode baru. Menambahkan Opcode baru membutuhkan banyak diskusi dan pengujian dan perubahan ini memperkenalkan Opcode baru. Opcode dipilih oleh proses kompilasi di CPython. Setelah kode Anda diubah menjadi Abstract-Syntax-Tree, kompilator mengeksplorasi setiap cabang dan mengubahnya menjadi Opcodes. Eksekusi kode Anda melewati Opcodes dalam pernyataan switch besar-besaran di dalam satu loop dan memanggil berbagai fungsi-C untuk setiap opcode.

Untuk referensi, Python 3.6 memiliki 3 Opcodes untuk fungsi panggilan. Semua ini ditambahkan atau dimodifikasi dengan Python 3.6.

  • Untuk memanggil fungsi argument-only functions: CALL_FUNCTION ,
  • Untuk memanggil fungsi posisi dan kata kunci: CALL_FUNCTION_KW,
  • Untuk memanggil fungsi posisi atau kata kunci variabel:CALL_FUNCTION_EX

Python 3.7 menambahkan 2 Opcode baru, LOAD_METHOD dan CALL_METHOD ketika compiler melihatnya x.method(…) menggunakan Opcode baru ini.

Sebagai contoh memanggil 3 fungsi dengan tanda berbeda:

from dis import dis          

               def function():

                   return 1           

               def function_args(arg1):

                   return arg1     

               def function_kwargs(arg1=None):

                   return arg1     

               def test():

                   function()

                   function_args(1)

                   function_kwargs(arg1=1)         

               dis(test)

Menjalankan ini pada Python 3.6 dan Python 3.7 kita dapat melihat tidak ada perubahan dalam kode yang dihasilkan atau kinerja.

Contoh lain dengan metode terikat (yaitu milik sebuah instance dari kelas),

from dis import dis          

               class TestClass(object):

                   def function():

                       return 1       

                   def function_args(arg1):

                       return arg1 

                   def function_kwargs(arg1=None):

                       return arg1 

               def test():

                   i = TestClass()

                   i.function()

                   i.function_args(1)

                   i.function_kwargs(arg1=1)       

               dis(test)

Hasil uji coba ini:

  • LOAD_METHOD Opcode baru menggantikan metode pembebanan yang terikat sebagai atribut dan hanya memanggilnya sebagai fungsi normal. Ingat, LOAD_METHOD dan CALL_METHOD lebih cepat daripada CALL_FUNCTION metode instan.
  • Metode terikat dengan kata kunci-argumen sama dengan Python 3.6, Anda tidak akan mendapatkan perubahan kinerja.
  • Metode terikat tanpa argumen sekarang lebih cepat

LOAD_METHOD menggantikan LOAD_ATTR yang pada dasarnya mendapatkan contoh BoundMethod pada instance objek. LOAD_METHOD adalah salinan dari logika di LOAD_ATTR tetapi lebih dioptimalkan ketika metode belum ditimpa dan memiliki argumen posisional.

Keluar dari ini Anda mungkin memiliki beberapa pertanyaan

Jadi jika saya menempatkan fungsi saya ke dalam kelas, akankah itu membuatnya lebih cepat?

Tidak, karena peningkatan kecepatan ini adalah untuk menghapus perlambatan terkait objek

Tentang Kata Kunci dan Argumen Variabel apakah mereka mendapatkan perlakuan khusus?

Argumen kata kunci memerlukan perlakuan khusus dalam loop eksekusi karena tidak ada ekuivalen dalam C (yang ditulis CPython), beberapa kode tambahan harus mengkompilasi 2 tupel agar lolos ke metode.

Argumen variabel, apakah posisi atau kata kunci juga memerlukan perlakuan khusus.

Begitu banyak peringatan, saya suka kata kunci-argumen, apakah saya akan melihat perbedaan?

Perubahan ini harus mendorong Anda dalam desain kelas untuk mengikuti prinsip DRY (don’t repeat yourself) dan tambahkan metode pribadi yang mengurangi duplikasi logika di beberapa metode publik. Sebelum 3.7, pukulan kinerja akan menjadi pertimbangan yang kuat dan menyalin + kode paste adalah praktik yang diterima di mana kecepatan diperlukan. Di masa depan kita mungkin melihat lebih banyak skenario menjalani perawatan serupa.

  1. str.find () lebih cepat untuk beberapa karakter

Beberapa karakter unicode memiliki masalah yang tidak menguntungkan ketika memindai string seperti kejadian menggunakan str.find(x), hingga 25x memperlambat.

$ ./python -m perf timeit -s ‘s = “一丁丂七丄丅丆万丈三上下丌不与丏丐丑丒专且丕世丗丘丙业丛东丝丞丟丠両丢丣两严並丧丨丩个丫丬中丮丯丰丱串丳临丵丶丷丸丹为主丼丽举丿乀乁乂乃乄久乆乇么义乊之乌乍乐乑乒乓乔乕乖乗乘乙乚乛乜九乞也习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯买乱乲乳乴乵乶乷乸乹乺乻乼乽乾乿亀亁亂亃亄亅了亇予争 亊事二亍于亏亐云互亓五井亖亗亘亙亚些亜亝亞亟亠亡亢亣交亥亦产亨亩亪享京亭亮亯亰亱亲亳亴亵亶亷亸亹人亻亼亽亾亿什仁仂仃仄仅仆仇仈仉今介仌仍从仏仐仑仒仓仔仕他仗付仙仚仛仜 仝仞仟仠仡仢代令以仦仧仨仩仪仫们仭仮仯仰仱仲仳仴仵件价仸仹仺任仼份仾仿”*100’ — ‘s.find(“乎”)’

Unpatched:  Median +- std dev: 761 us +- 108 us

Patched:    Median +- std dev: 117 us +- 9 us

Dalam Python 3.7, ukuran kode-kode Unicode yang diharapkan tidak lagi dikodekan dan metode dioptimalkan untuk karakter yang panjang (kebanyakan tidak biasa).

Ini masih lebih lambat, tetapi sekarang 3x lebih lambat daripada karakter ASCII, bukan 25x!

  1. os.fwalk 2x lebih cepat

Fwalk fungsi dalam os modul (hanya di Python 3) adalah generator direktori-tree. Ia berperilaku persis seperti walk(), kecuali ketika ia menghasilkan respons 4-tupel (dirpath, dirnames, filenames, dirfd

Perubahan adalah untuk mengubah pelaksanaan untuk menggunakan scandir metode bukan listdir agar Operasi Sistem dioptimalkan dan lebih cepat.

  1. Ekspresi reguler lebih cepat *

Dalam modul regular-expression ( re) ada metode compile yang mengkompilasi string ekspresi reguler dan seperangkat flag opsional. Flag ini dapat berupa flag RegEx, diteruskan ke pustaka RegEx.

Perubahan dibuat dengan Python 3.6 yang memperlambat panggilan ini ketika flag dilewatkan yang merupakan bilangan bulat. Python 3.7 “perbaikan” mengalami perlambatan yang masih tidak secepat Python 3.5.

  1. Ekspresi reguler lebih cepat untuk pencocokan case-sensitive

Per perubahan perubahan log

Mencocokkan dan mencari ekspresi reguler case-insensitive jauh lebih lambat daripada mencocokkan dan mencari ekspresi reguler case-sensitive. Case-insensitivity membutuhkan mengkonversi setiap karakter dalam string input ke huruf kecil dan menonaktifkan beberapa optimasi. Namun hanya ada 2669 karakter casing (52 dalam mode ASCII). Untuk semua karakter lain dalam pola, kita dapat menggunakan pencocokan peka huruf besar kecil.

Peningkatan kecepatan signifikan, jika Anda mencocokkan karakter ASCII Anda dapat melihat peningkatan hingga 20x dalam waktu yang sesuai karena sekarang melakukan pencarian alih-alih menjalankan lower()setiap karakter.

Leave a Reply

Your email address will not be published. Required fields are marked *