Multicore Python: Matlamat yang sukar, layak dan boleh dicapai

Untuk semua ciri Python yang hebat dan senang, satu matlamat tetap tidak dapat dicapai: Aplikasi Python berjalan pada jurubahasa rujukan CPython dan menggunakan beberapa teras CPU secara selari.

Ini telah lama menjadi salah satu batu sandungan terbesar Python, terutama kerana semua jalan keluarnya kekok. Urgensi untuk mencari penyelesaian jangka panjang untuk masalah ini semakin meningkat, terutama kerana teras pada pemproses terus meningkat (lihat raksasa 24-teras Intel).

Satu kunci untuk semua

Sebenarnya, mungkin menggunakan benang dalam aplikasi Python - banyak yang sudah ada. Yang  tidak mustahil adalah CPython menjalankan aplikasi multithreaded dengan setiap thread dijalankan secara selari pada teras yang berbeza. Pengurusan memori dalaman CPython tidak selamat untuk thread, jadi jurubahasa hanya menjalankan satu utas pada satu masa, beralih di antara mereka mengikut keperluan dan mengawal akses ke keadaan global.

Mekanisme penguncian ini, Global Interpreter Lock (GIL), adalah satu-satunya sebab terbesar mengapa CPython tidak dapat menjalankan utas secara selari. Terdapat beberapa faktor pengurangan; sebagai contoh, operasi I / O seperti pembacaan cakera atau rangkaian tidak terikat oleh GIL, jadi operasi tersebut dapat berjalan dengan bebas di utas mereka sendiri. Tetapi apa-apa yang terdiri daripada multithreaded dan CPU adalah masalah.

Bagi pengaturcara Python, ini bermaksud tugas-tugas komputasi berat yang mendapat manfaat daripada penyebaran di beberapa teras tidak berjalan dengan baik, melarang penggunaan perpustakaan luaran. Kemudahan bekerja di Python datang dengan kos prestasi yang besar, yang menjadi lebih sukar untuk ditelan dengan lebih cepat, bahasa yang sama mudahnya seperti Google's Go muncul.

Pilih kunci

Lama kelamaan, banyak pilihan telah muncul yang memperbaiki - tetapi tidak menghilangkan - had GIL. Salah satu taktik standard adalah melancarkan beberapa contoh CPython dan berkongsi konteks dan keadaan di antara mereka; setiap contoh berjalan bebas dari yang lain dalam proses yang berasingan. Tetapi seperti yang dijelaskan oleh Jeff Knupp, keuntungan yang diberikan dengan berjalan secara selari dapat hilang dengan usaha yang diperlukan untuk berkongsi keadaan, jadi teknik ini sangat sesuai untuk operasi jangka panjang yang mengumpulkan hasilnya dari masa ke masa.

Sambungan C tidak terikat oleh GIL, begitu banyak perpustakaan untuk Python yang memerlukan kepantasan (seperti perpustakaan matematik dan statistik Numpy) dapat berjalan di beberapa teras. Tetapi had dalam CPython itu sendiri tetap ada. Sekiranya kaedah terbaik untuk mengelakkan GIL adalah menggunakan C, itu akan mendorong lebih banyak pengaturcara pergi dari Python dan menuju ke C.

PyPy, versi Python yang menyusun kod melalui JIT, tidak menyingkirkan GIL tetapi menebusnya dengan hanya menjalankan kod lebih cepat. Dalam beberapa cara, ini bukan pengganti yang buruk: Sekiranya kepantasan adalah sebab utama anda melihat multithreading, PyPy mungkin dapat memberikan halaju tanpa komplikasi multithreading.

Akhirnya, GIL itu sendiri dikerjakan semula di Python 3, dengan pengendali pertukaran benang yang lebih baik. Tetapi semua andaian yang mendasari - dan batasan - tetap ada. Masih ada GIL, dan masih meneruskan prosiding.

Tiada GIL? Tiada masalah

Walaupun begitu, pencarian Python tanpa GIL, sesuai dengan aplikasi yang ada, tetap diteruskan. Pelaksanaan Python yang lain telah menghapuskan GIL sepenuhnya, tetapi dengan kosnya. Jython, misalnya, berjalan di atas JVM dan menggunakan sistem penjejakan objek JVM dan bukannya GIL. IronPython mengambil pendekatan yang sama melalui CLR Microsoft. Tetapi kedua-duanya mengalami prestasi yang tidak konsisten, dan kadang-kadang mereka berjalan jauh lebih lambat daripada CPython. Mereka juga tidak dapat berinteraksi dengan mudah dengan kod C luaran, jadi banyak aplikasi Python yang ada tidak akan berfungsi.

PyParallel, sebuah projek yang dibuat oleh Trent Nelson dari Continuum Analytics, adalah "percubaan, garpu bukti konsep Python 3 yang dirancang untuk mengeksploitasi banyak teras CPU secara optimum." Ia tidak menghilangkan GIL, tetapi memperbaiki kesannya dengan mengganti asyncmodul, jadi aplikasi yang menggunakan  asyncparalelisme (seperti I / O multithreaded seperti pelayan web) mendapat banyak manfaat. Projek ini tidak aktif selama beberapa bulan, tetapi dokumentasinya menyatakan bahawa pembangunnya selesa meluangkan masa untuk memperbaikinya, sehingga akhirnya dapat dimasukkan ke dalam CPython: "Tidak ada yang salah dengan lambat dan stabil selama anda menuju ke arah yang betul. "

Satu projek yang telah lama dijalankan oleh pencipta PyPy adalah versi Python yang menggunakan teknik yang disebut "memori transaksional perisian" (PyPy-STM). Kelebihannya, menurut pencipta PyPy, adalah "anda boleh melakukan sedikit perubahan terhadap program anda yang sudah ada dan bukan multithreaded dan membuatnya dapat menggunakan banyak core."

PyPy-STM terdengar seperti sihir, tetapi ia mempunyai dua kelemahan. Pertama, ia sedang dijalankan yang kini hanya menyokong Python 2.x, dan kedua, ia masih memerlukan prestasi untuk aplikasi yang berjalan pada satu teras. Oleh kerana salah satu ketetapan yang dikutip oleh pencipta Python, Guido van Rossum untuk sebarang percubaan untuk menghapus GIL dari CPython adalah bahawa penggantiannya tidak boleh menurunkan prestasi untuk aplikasi single-threaded, single-threaded, perbaikan seperti ini tidak akan berlaku di CPython dalam keadaan sekarang.

Cepat dan tunggu

Larry Hastings, pemaju inti Python, berkongsi beberapa pandangannya di PyCon 2016 mengenai bagaimana GIL dapat dikeluarkan. Hastings mendokumentasikan percubaannya untuk menghapus GIL dan dengan melakukannya berakhir dengan versi Python yang tidak mempunyai GIL, tetapi berlari dengan perlahan kerana cache yang berterusan.

Anda boleh kehilangan GIL, Hastings disimpulkan, tetapi anda perlu mempunyai cara untuk menjamin bahawa hanya satu utas pada satu masa yang mengubah objek global - misalnya, dengan mempunyai utas khusus dalam jurubahasa menangani perubahan keadaan tersebut.

Satu berita baik jangka panjang adalah bahawa jika dan ketika CPython menumpahkan GIL, pengembang yang menggunakan bahasa itu sudah siap untuk memanfaatkan multithreading. Banyak perubahan yang kini dimasukkan ke dalam sintaks Python, seperti antrian dan async/ awaitkata kunci untuk Python 3.5, mempermudah tugas dalam merentasi inti pada tahap tinggi.

Masih, jumlah kerja yang diperlukan untuk menjadikan Python GIL kurang semua tetapi menjamin ia akan muncul pertama dalam pelaksanaan yang berasingan seperti PyPy-STM. Mereka yang ingin mencuba sistem tanpa GIL boleh melakukannya melalui usaha pihak ketiga seperti itu, tetapi CPython yang asli mungkin masih belum tersentuh buat masa ini. Di sini berharap penantian tidak lebih lama.