Apa itu Cython? Python dengan kecepatan C

Python memiliki reputasi sebagai salah satu bahasa pemrograman yang paling nyaman, lengkap, dan benar-benar berguna. Kecepatan eksekusi? Tidak terlalu banyak.

Masukkan Cython. Bahasa Cython adalah superset dari Python yang dikompilasi ke C, menghasilkan peningkatan kinerja yang dapat berkisar dari beberapa persen hingga beberapa kali lipat, tergantung pada tugas yang ada. Untuk pekerjaan yang terikat oleh jenis objek asli Python, percepatannya tidak akan besar. Tetapi untuk operasi numerik, atau operasi apa pun yang tidak melibatkan internal Python sendiri, keuntungannya bisa sangat besar. 

Dengan Cython, Anda dapat melewati banyak batasan asli Python atau melampauinya sepenuhnya — tanpa harus melepaskan kemudahan dan kenyamanan Python. Dalam artikel ini, kita akan membahas konsep dasar di balik Cython dan membuat aplikasi Python sederhana yang menggunakan Cython untuk mempercepat salah satu fungsinya.

Video terkait: Menggunakan Cython untuk mempercepat Python

Kompilasi Python ke C

Kode Python dapat melakukan panggilan langsung ke modul C. Modul C tersebut dapat berupa pustaka C generik atau pustaka yang dibuat khusus untuk bekerja dengan Python. Cython menghasilkan modul jenis kedua: perpustakaan C yang berbicara dengan internal Python, dan yang dapat digabungkan dengan kode Python yang ada.

Kode Cython sangat mirip dengan kode Python, secara desain. Jika Anda memberi makan kompiler Cython sebuah program Python (Python 2.x dan Python 3.x keduanya didukung), Cython akan menerimanya apa adanya, tetapi tidak ada akselerasi asli Cython yang akan ikut bermain. Tetapi jika Anda menghias kode Python dengan anotasi tipe dalam sintaks khusus Cython, Cython akan dapat menggantikan ekuivalen C cepat untuk objek Python lambat.

Perhatikan bahwa pendekatan Cython bersifat  inkremental . Itu berarti pengembang dapat mulai dengan  aplikasi Python yang ada , dan mempercepatnya dengan membuat perubahan langsung pada kode, daripada menulis ulang seluruh aplikasi dari awal.

Pendekatan ini sesuai dengan sifat masalah kinerja perangkat lunak secara umum. Di sebagian besar program, sebagian besar kode intensif CPU terkonsentrasi di beberapa hot spot — versi prinsip Pareto, juga dikenal sebagai aturan "80/20". Jadi sebagian besar kode dalam aplikasi Python tidak perlu dioptimalkan kinerjanya, hanya beberapa bagian penting. Anda dapat secara bertahap menerjemahkan titik-titik panas tersebut ke dalam Cython, dan mendapatkan peningkatan kinerja yang Anda butuhkan di tempat yang paling penting. Program lainnya dapat tetap menggunakan Python demi kenyamanan pengembang.

Cara menggunakan Cython

Perhatikan kode berikut, diambil dari dokumentasi Cython:

def f (x):

    return x ** 2-x

def integrated_f (a, b, N):

    s = 0

    dx = (ba) / N

    untuk i dalam rentang (N):

        s + = f (a + i * dx)

    kembali s * dx

Ini adalah contoh mainan, implementasi fungsi integral yang tidak terlalu efisien. Sebagai kode Python murni, ini lambat, karena Python harus mengonversi bolak-balik antara tipe numerik asli mesin dan tipe objek internalnya sendiri.

Sekarang pertimbangkan versi Cython dari kode yang sama, dengan penambahan Cython yang digarisbawahi:

 cdef ganda f (ganda x):

    return x ** 2-x

def integr_f (double a, double b, int N):

    cdef int i

    cdef ganda s, x, dx

    s = 0

    dx = (ba) / N

    untuk i dalam rentang (N):

        s + = f (a + i * dx)

    kembali s * dx

Jika kita secara eksplisit menyatakan jenis variabel, baik untuk parameter fungsi dan variabel yang digunakan dalam tubuh fungsi ( double, int, dll), Cython akan menerjemahkan semua ini menjadi C. Kami juga dapat menggunakan cdefkata kunci untuk menentukan fungsi yang diimplementasikan terutama dalam C untuk kecepatan tambahan, meskipun fungsi tersebut hanya dapat dipanggil oleh fungsi Cython lainnya dan bukan oleh skrip Python. (Dalam contoh di atas, hanya integrate_fdapat dipanggil oleh skrip Python lain.)

Perhatikan betapa sedikit perubahan kode kita yang sebenarnya  . Semua yang kami lakukan adalah menambahkan deklarasi tipe ke kode yang ada untuk mendapatkan peningkatan kinerja yang signifikan.

Keunggulan Cython

Selain bisa mempercepat kode yang sudah Anda tulis, Cython memberikan beberapa keuntungan lain:

Bekerja dengan pustaka C eksternal bisa lebih cepat

Paket Python seperti NumPy membungkus pustaka C dengan antarmuka Python untuk membuatnya mudah digunakan. Namun, bolak-balik antara Python dan C melalui pembungkus itu dapat memperlambat segalanya. Cython memungkinkan Anda berbicara dengan pustaka yang mendasarinya secara langsung, tanpa dihalangi Python. (Pustaka C ++ juga didukung.)

Anda dapat menggunakan manajemen memori C dan Python

Jika Anda menggunakan objek Python, objek tersebut dikelola oleh memori dan sampah dikumpulkan sama seperti di Python biasa. Tetapi jika Anda ingin membuat dan mengelola struktur tingkat-C Anda sendiri, dan menggunakan malloc/ freeuntuk bekerja dengannya, Anda dapat melakukannya. Ingatlah untuk membersihkan diri sendiri.

Anda dapat memilih keamanan atau kecepatan sesuai kebutuhan 

Cython secara otomatis melakukan pemeriksaan runtime untuk masalah umum yang muncul di C, seperti akses di luar batas pada sebuah array, dengan cara dekorator dan arahan kompilator (misalnya, @boundscheck(False)). Akibatnya, kode C yang dihasilkan oleh Cython jauh lebih aman secara default daripada kode C linting tangan, meskipun berpotensi dengan mengorbankan kinerja mentah.

Jika Anda yakin tidak memerlukan pemeriksaan tersebut pada waktu proses, Anda dapat menonaktifkannya untuk mendapatkan kecepatan tambahan, baik di seluruh modul atau hanya pada fungsi tertentu.

Cython juga memungkinkan Anda untuk mengakses struktur Python secara native yang menggunakan protokol buffer untuk akses langsung ke data yang disimpan dalam memori (tanpa penyalinan perantara). Tampilan memori Cython memungkinkan Anda bekerja dengan struktur tersebut dengan kecepatan tinggi, dan dengan tingkat keamanan yang sesuai untuk tugas tersebut. Misalnya, data mentah yang mendasari string Python dapat dibaca dengan cara ini (cepat) tanpa harus melalui runtime Python (lambat).

Kode Cython C bisa mendapatkan keuntungan dari merilis GIL

Kunci Penerjemah Global Python, atau GIL, menyinkronkan utas di dalam penerjemah, melindungi akses ke objek Python dan mengelola perselisihan untuk sumber daya. Tetapi GIL telah banyak dikritik sebagai batu sandungan bagi Python yang berkinerja lebih baik, terutama pada sistem multicore.

Jika Anda memiliki bagian kode yang tidak membuat referensi ke objek Python dan menjalankan operasi jangka panjang, Anda dapat menandainya dengan  with nogil:arahan untuk mengizinkannya berjalan tanpa GIL. Ini membebaskan penerjemah Python untuk melakukan hal-hal lain, dan memungkinkan kode Cython untuk menggunakan banyak inti (dengan pekerjaan tambahan).

Cython dapat menggunakan sintaks petunjuk tipe Python 

Python memiliki sintaks petunjuk tipe yang digunakan terutama oleh linter dan pemeriksa kode, bukan interpreter CPython. Cython memiliki sintaks kustom sendiri untuk dekorasi kode, tetapi dengan revisi terbaru dari Cython Anda dapat menggunakan sintaks petunjuk tipe Python untuk memberikan petunjuk tipe dasar ke Cython juga. 

Cython dapat digunakan untuk mengaburkan kode Python yang sensitif

Modul Python sangat mudah untuk didekompilasi dan diperiksa, tetapi binari yang dikompilasi tidak. Saat mendistribusikan aplikasi Python ke pengguna akhir, jika Anda ingin melindungi beberapa modulnya dari pengintaian biasa, Anda dapat melakukannya dengan mengompilasinya dengan Cython. Namun, perhatikan, ini adalah efek samping dari kemampuan Cython, bukan salah satu fungsi yang dimaksudkan.

Batasan Cython

Perlu diingat bahwa Cython bukanlah tongkat ajaib. Itu tidak secara otomatis mengubah setiap contoh kode Python poky menjadi kode C yang sangat cepat. Untuk memanfaatkan Cython secara maksimal, Anda harus menggunakannya dengan bijak — dan memahami batasannya:

Sedikit percepatan untuk kode Python konvensional

Ketika Cython menemukan kode Python, ia tidak dapat menerjemahkan sepenuhnya ke dalam C, ia mengubah kode itu menjadi serangkaian panggilan C ke internal Python. Ini berarti mengeluarkan interpreter Python dari loop eksekusi, yang memberikan kode kecepatan 15 hingga 20 persen sederhana secara default. Perhatikan bahwa ini adalah skenario kasus terbaik; dalam beberapa situasi, Anda mungkin tidak melihat peningkatan kinerja, atau bahkan penurunan kinerja.

Sedikit percepatan untuk struktur data Python asli

Python menyediakan banyak sekali struktur data — string, daftar, tupel, kamus, dan sebagainya. Mereka sangat nyaman untuk pengembang, dan mereka datang dengan manajemen memori otomatis mereka sendiri. Tapi mereka lebih lambat dari C murni.

Cython memungkinkan Anda terus menggunakan semua struktur data Python, meskipun tanpa banyak percepatan. Ini, sekali lagi, karena Cython hanya memanggil C API di runtime Python yang membuat dan memanipulasi objek tersebut. Jadi struktur data Python berperilaku seperti kode Python yang dioptimalkan untuk Cython pada umumnya: Anda terkadang mendapatkan dorongan, tetapi hanya sedikit. Untuk hasil terbaik, gunakan variabel dan struktur C. Kabar baiknya adalah Cython memudahkan untuk bekerja dengan mereka.

Kode Cython berjalan tercepat saat "C murni"

Jika Anda memiliki fungsi di C yang diberi label dengan cdefkata kunci, dengan semua variabel dan fungsi sebaris memanggil ke hal lain yang murni C, itu akan berjalan secepat C bisa pergi. Tetapi jika fungsi itu mereferensikan kode asli Python apa pun, seperti struktur data Python atau panggilan ke API Python internal, panggilan itu akan menjadi hambatan kinerja.

Untungnya, Cython menyediakan cara untuk menemukan kemacetan ini: laporan kode sumber yang menunjukkan sekilas bagian mana dari aplikasi Cython Anda yang murni C dan bagian mana yang berinteraksi dengan Python. Semakin baik aplikasi yang dioptimalkan, semakin sedikit interaksi dengan Python.

Cython NumPy 

Cython meningkatkan penggunaan pustaka pengolah angka pihak ketiga berbasis C seperti NumPy. Karena kode Cython dikompilasi ke C, ia dapat berinteraksi dengan pustaka itu secara langsung, dan menghilangkan kemacetan Python dari perulangan.

Tapi NumPy, khususnya, bekerja dengan baik dengan Cython. Cython memiliki dukungan asli untuk konstruksi tertentu di NumPy dan menyediakan akses cepat ke array NumPy. Dan sintaks NumPy yang sama yang Anda gunakan dalam skrip Python konvensional dapat digunakan di Cython apa adanya.

Namun, jika Anda ingin membuat binding yang paling mendekati antara Cython dan NumPy, Anda perlu menghias kode lebih lanjut dengan sintaks kustom Cython. The  cimportpernyataan, misalnya, memungkinkan kode Cython untuk melihat konstruksi C-tingkat di perpustakaan pada waktu kompilasi untuk binding tercepat mungkin.

Karena NumPy digunakan secara luas, Cython mendukung NumPy "di luar kotak". Jika Anda telah menginstal NumPy, Anda dapat menyatakannya  cimport numpy di kode Anda, lalu menambahkan dekorasi lebih lanjut untuk menggunakan fungsi yang terbuka. 

Profil dan kinerja Cython

Anda mendapatkan kinerja terbaik dari setiap bagian kode dengan membuat profil dan melihat secara langsung di mana kemacetannya. Cython menyediakan kait untuk modul cProfile Python, sehingga Anda dapat menggunakan alat pembuatan profil Python sendiri, seperti cProfile, untuk melihat bagaimana kinerja kode Cython Anda. 

Sangat membantu untuk mengingat dalam semua kasus bahwa Cython bukanlah sihir — bahwa praktik kinerja dunia nyata yang masuk akal masih berlaku. Semakin sedikit Anda melakukan bolak-balik antara Python dan Cython, semakin cepat aplikasi Anda akan berjalan.

Misalnya, jika Anda memiliki kumpulan objek yang ingin Anda proses di Cython, jangan mengulanginya dengan Python dan menjalankan fungsi Cython di setiap langkah. Teruskan seluruh koleksi ke modul Cython Anda dan lakukan iterasi di sana. Teknik ini sering digunakan di pustaka yang mengelola data, jadi ini adalah model yang baik untuk ditiru dalam kode Anda sendiri.

Kami menggunakan Python karena memberikan kemudahan programmer dan memungkinkan pengembangan yang cepat. Kadang-kadang produktivitas pemrogram mengorbankan kinerja. Dengan Cython, hanya sedikit usaha ekstra yang dapat memberikan Anda yang terbaik dari kedua dunia.

Baca lebih lanjut tentang Python

  • Apa itu Python? Pemrograman yang kuat dan intuitif
  • Apa itu PyPy? Python lebih cepat tanpa rasa sakit
  • Apa itu Cython? Python dengan kecepatan C
  • Tutorial Cython: Cara mempercepat Python
  • Cara menginstal Python dengan cara cerdas
  • Fitur baru terbaik di Python 3.8
  • Manajemen proyek Python yang lebih baik dengan Poetry
  • Virtualenv dan venv: Penjelasan lingkungan virtual Python
  • Python virtualenv dan venv lakukan dan tidak boleh dilakukan
  • Penjelasan threading dan subproses Python
  • Cara menggunakan debugger Python
  • Cara menggunakan timeit untuk membuat profil kode Python
  • Cara menggunakan cProfile untuk membuat profil kode Python
  • Mulailah dengan async dengan Python
  • Cara menggunakan asyncio dengan Python
  • Cara mengonversi Python ke JavaScript (dan kembali lagi)
  • Python 2 EOL: Cara bertahan dari akhir Python 2
  • 12 Pythons untuk setiap kebutuhan pemrograman
  • 24 perpustakaan Python untuk setiap pengembang Python
  • 7 IDE Python manis yang mungkin Anda lewatkan
  • 3 kekurangan utama Python — dan solusinya
  • 13 kerangka web Python dibandingkan
  • 4 kerangka uji Python untuk menghancurkan bug Anda
  • 6 fitur Python baru yang hebat yang tidak ingin Anda lewatkan
  • 5 distribusi Python untuk menguasai pembelajaran mesin
  • 8 perpustakaan Python yang bagus untuk pemrosesan bahasa alami