Bagi saya ini sebenarnya cukup sederhana:
The subproses opsi:
subprocess
adalah untuk menjalankan executable lain --- pada dasarnya ini adalah pembungkus os.fork()
dan os.execve()
dengan beberapa dukungan untuk pipa saluran opsional (menyiapkan PIPE ke dan dari subproses. Jelas Anda dapat mekanisme komunikasi antar proses (IPC) lainnya, seperti soket, atau Posix atau Memori bersama SysV. Tetapi Anda akan dibatasi pada antarmuka dan saluran IPC apa pun yang didukung oleh program yang Anda panggil.
Umumnya, seseorang menggunakan sembarang subprocess
- cukup memanggil beberapa utilitas eksternal dan membaca kembali outputnya atau menunggu penyelesaiannya (mungkin membaca hasilnya dari file sementara, atau setelah diposting ke beberapa database).
Namun seseorang dapat menelurkan ratusan subproses dan melakukan polling. Classh utilitas favorit pribadi saya melakukan hal itu.
Kerugian terbesar dari subprocess
modul ini adalah dukungan I / O umumnya memblokir. Ada draf PEP-3145 untuk memperbaikinya di beberapa versi Python 3.x yang akan datang dan asyncproc alternatif (Peringatan yang mengarahkan hak ke unduhan, bukan ke dokumentasi atau README). Saya juga menemukan bahwa relatif mudah untuk hanya mengimpor fcntl
dan memanipulasi Popen
deskriptor file PIPE Anda secara langsung --- meskipun saya tidak tahu apakah ini portabel untuk platform non-UNIX.
(Pembaruan: 7 Agustus 2019: Dukungan Python 3 untuk subproses ayncio : Subproses asyncio )
subprocess
hampir tidak memiliki dukungan penanganan peristiwa ... meskipun Anda dapat menggunakan signal
modul dan sinyal UNIX / Linux jadul biasa --- mematikan proses Anda dengan lembut, seolah-olah.
The multiprocessing opsi:
multiprocessing
adalah untuk menjalankan fungsi dalam kode (Python) yang ada dengan dukungan untuk komunikasi yang lebih fleksibel di antara rangkaian proses ini. Secara khusus, yang terbaik adalah membangun multiprocessing
IPC Anda di sekitar objek modul Queue
jika memungkinkan, tetapi Anda juga dapat menggunakan Event
objek dan berbagai fitur lainnya (beberapa di antaranya, mungkin, dibangun di sekitar mmap
dukungan pada platform di mana dukungan itu cukup).
multiprocessing
Modul Python dimaksudkan untuk menyediakan antarmuka dan fitur yang sangat mirip dengan threading
sementara memungkinkan CPython untuk menskalakan pemrosesan Anda di antara banyak CPU / core meskipun ada GIL (Global Interpreter Lock). Ini memanfaatkan semua penguncian SMP dan upaya koherensi yang dilakukan oleh pengembang kernel OS Anda.
The threading opsi:
threading
adalah untuk rentang aplikasi yang cukup sempit yang terikat I / O (tidak perlu diskalakan di beberapa inti CPU) dan yang diuntungkan dari latensi yang sangat rendah dan overhead switching dari peralihan thread (dengan memori inti bersama) vs. proses / pengalihan konteks. Di Linux ini hampir merupakan himpunan kosong (waktu peralihan proses Linux sangat dekat dengan sakelar utasnya).
threading
menderita dua kelemahan utama dengan Python .
Satu, tentu saja, adalah implementasi spesifik --- kebanyakan mempengaruhi CPython. Itulah GIL. Untuk sebagian besar, sebagian besar program CPython tidak akan mendapatkan keuntungan dari ketersediaan lebih dari dua CPU (inti) dan seringkali kinerja akan menderita karena pertentangan penguncian GIL.
Masalah yang lebih besar yang tidak spesifik untuk implementasi, adalah bahwa utas berbagi memori yang sama, penangan sinyal, deskriptor file, dan sumber daya OS tertentu lainnya. Oleh karena itu, programmer harus sangat berhati-hati tentang penguncian objek, penanganan pengecualian, dan aspek lain dari kode mereka yang tidak kentara dan dapat mematikan, menghentikan, atau menghentikan keseluruhan proses (rangkaian utas).
Sebagai perbandingan, multiprocessing
model memberikan setiap proses memorinya sendiri, deskriptor file, dll. Sebuah error atau pengecualian yang tidak tertangani di salah satu dari mereka hanya akan mematikan sumber daya itu dan menangani hilangnya proses anak atau saudara secara kuat bisa jauh lebih mudah daripada debugging, mengisolasi dan memperbaiki atau mengatasi masalah serupa di utas.
- (Catatan: penggunaan
threading
dengan sistem Python utama, seperti NumPy , mungkin menderita lebih sedikit dari pertentangan GIL daripada kebanyakan kode Python Anda sendiri. Itu karena mereka telah direkayasa secara khusus untuk melakukannya; bagian asli / biner dari NumPy, misalnya, akan merilis GIL saat itu aman).
The bengkok opsi:
Perlu juga dicatat bahwa Twisted menawarkan alternatif lain yang elegan dan sangat menantang untuk dipahami . Pada dasarnya, dengan risiko terlalu menyederhanakan ke titik di mana penggemar Twisted dapat menyerbu rumah saya dengan garpu rumput dan obor, Twisted menyediakan multi-tasking koperasi yang digerakkan oleh acara dalam proses (tunggal) apa pun.
Untuk memahami bagaimana hal ini dimungkinkan, seseorang harus membaca tentang fitur-fitur select()
(yang dapat dibangun di sekitar select () atau poll () atau panggilan sistem OS serupa). Pada dasarnya itu semua didorong oleh kemampuan untuk membuat permintaan OS untuk tidur sambil menunggu aktivitas apa pun di daftar deskriptor file atau beberapa waktu tunggu.
Kebangkitan dari masing-masing panggilan ini ke select()
adalah sebuah peristiwa --- baik yang melibatkan input yang tersedia (dapat dibaca) pada sejumlah soket atau deskriptor file, atau ruang buffer menjadi tersedia pada beberapa deskriptor atau soket lain (dapat ditulis), beberapa kondisi luar biasa (TCP out-of-band PUSH'd packets, misalnya), atau TIMEOUT.
Jadi, model pemrograman Twisted dibangun untuk menangani kejadian ini kemudian melakukan perulangan pada pengendali "utama" yang dihasilkan, memungkinkannya untuk mengirimkan kejadian ke penangan Anda.
Saya pribadi menganggap nama, Twisted sebagai menggugah model pemrograman ... karena pendekatan Anda terhadap masalah harus, dalam arti tertentu, "dipelintir" dari dalam ke luar. Daripada menganggap program Anda sebagai rangkaian operasi pada data masukan dan keluaran atau hasil, Anda menulis program Anda sebagai layanan atau daemon dan menentukan bagaimana reaksinya terhadap berbagai peristiwa. (Sebenarnya inti "putaran utama" dari program Twisted adalah (biasanya? Selalu?) A reactor()
).
The tantangan besar untuk menggunakan twisted melibatkan memutar pikiran Anda sekitar acara didorong Model dan juga menghindari penggunaan setiap perpustakaan kelas atau toolkit yang tidak ditulis untuk bekerja sama dalam kerangka twisted. Inilah sebabnya mengapa Twisted menyediakan modulnya sendiri untuk penanganan protokol SSH, untuk kutukan, dan subproses / fungsi Popennya sendiri, dan banyak modul dan penangan protokol lainnya yang, pada awalnya, akan terlihat menduplikasi hal-hal di pustaka standar Python.
Saya pikir itu berguna untuk memahami Twisted pada tingkat konseptual bahkan jika Anda tidak pernah berniat menggunakannya. Ini dapat memberikan wawasan tentang kinerja, perselisihan, dan penanganan acara dalam penanganan threading, multiprosesing dan bahkan subproses Anda serta setiap pemrosesan terdistribusi yang Anda lakukan.
( Catatan: Versi lebih baru dari Python 3.x termasuk fitur asyncio (asynchronous I / O) seperti async def , dekorator @ async.coroutine , dan kata kunci await , dan hasil dari dukungan di masa mendatang . Semua ini secara kasar mirip dengan Memutar dari perspektif proses (multitasking koperasi)). (Untuk status dukungan Twisted saat ini untuk Python 3, lihat: https://twistedmatrix.com/documents/current/core/howto/python3.html )
The didistribusikan opsi:
Namun bidang pemrosesan lain yang belum Anda tanyakan, tetapi yang patut dipertimbangkan, adalah pemrosesan terdistribusi . Ada banyak alat dan kerangka kerja Python untuk pemrosesan terdistribusi dan komputasi paralel. Secara pribadi saya pikir yang paling mudah digunakan adalah yang paling tidak sering dianggap ada di ruang itu.
Membangun pemrosesan terdistribusi di sekitar Redis hampir tidak mudah . Seluruh penyimpanan kunci dapat digunakan untuk menyimpan unit dan hasil kerja, Redis LIST dapat digunakan sebagai Queue()
objek sejenis, dan dukungan PUB / SUB dapat digunakan untuk Event
penanganan serupa. Anda dapat melakukan hashing pada kunci dan nilai penggunaan Anda, yang direplikasi di seluruh cluster instans Redis yang longgar, untuk menyimpan topologi dan pemetaan token hash guna memberikan hashing dan fail-over yang konsisten untuk penskalaan di luar kapasitas instans tunggal mana pun untuk mengoordinasikan pekerja Anda dan data marshaling (acar, JSON, BSON, atau YAML) di antaranya.
Tentu saja saat Anda mulai membangun skala yang lebih besar dan solusi yang lebih canggih di sekitar Redis, Anda menerapkan ulang banyak fitur yang telah diselesaikan menggunakan, Celery , Apache Spark dan Hadoop , Zookeeper , dlld , Cassandra , dan seterusnya. Semuanya memiliki modul untuk akses Python ke layanan mereka.
[Pembaruan: Beberapa sumber daya untuk dipertimbangkan jika Anda mempertimbangkan Python untuk komputasi intensif di seluruh sistem terdistribusi: IPython Parallel dan PySpark . Meskipun ini adalah sistem komputasi terdistribusi untuk tujuan umum, sistem ini sangat mudah diakses dan ilmu data subsistem dan analitik yang populer].
Kesimpulan
Di sana Anda memiliki keseluruhan alternatif pemrosesan untuk Python, dari utas tunggal, dengan panggilan sinkron sederhana ke sub-proses, kumpulan subproses yang disurvei, utas dan multiprosesing, multi-tasking koperasi yang digerakkan oleh peristiwa, dan keluar ke pemrosesan terdistribusi.