Alternatif yang bersih dan ringan untuk Python yang bengkok? [Tutup]

222

Beberapa waktu yang lalu saya menulis web-spider yang saya multithreaded untuk memungkinkan permintaan bersamaan terjadi pada saat yang sama. Itu di masa muda Python saya, pada hari-hari sebelum saya tahu tentang GIL dan kesengsaraan terkait yang dibuatnya untuk kode multithreaded (IE, sebagian besar waktu hanya berakhir serial!) ...

Saya ingin mengerjakan ulang kode ini agar lebih kuat dan berkinerja lebih baik. Pada dasarnya ada dua cara saya bisa melakukan ini: Saya bisa menggunakan modul multiprosesor baru di 2.6+ atau saya bisa menggunakan model semacam reaktor / event-based. Saya lebih suka melakukannya nanti karena itu jauh lebih sederhana dan lebih rentan kesalahan.

Jadi pertanyaannya terkait dengan kerangka kerja apa yang paling cocok dengan kebutuhan saya. Berikut ini adalah daftar opsi yang saya ketahui sejauh ini:

  • Twisted : Nenek dari kerangka kerja reaktor Python: tampaknya rumit dan sedikit membengkak. Curam kurva belajar untuk tugas kecil.
  • Eventlet : Dari orang-orang di lindenlab . Kerangka kerja berbasis Greenlet yang diarahkan pada tugas-tugas semacam ini. Saya telah melihat kode meskipun dan itu tidak terlalu cantik: non-pep8 compliant, tersebar dengan cetakan (mengapa orang melakukan ini dalam suatu kerangka kerja !?), API tampaknya sedikit tidak konsisten.
  • PyEv : Belum dewasa, sepertinya tidak ada orang yang menggunakannya sekarang meskipun didasarkan pada libevent sehingga punya backend yang solid.
  • asyncore : Dari stdlib: über level rendah, sepertinya banyak kerja keras yang terlibat hanya untuk mendapatkan sesuatu dari tanah.
  • tornado : Meskipun ini adalah produk berorientasi server yang dirancang untuk server situs web dinamis, ia menampilkan klien HTTP async dan ioloop sederhana . Sepertinya itu bisa menyelesaikan pekerjaan tetapi tidak untuk apa itu dimaksudkan. [edit: sayangnya tidak berjalan di Windows, yang penting bagi saya - ini merupakan persyaratan bagi saya untuk mendukung platform lumpuh ini]

Apakah ada sesuatu yang saya lewatkan? Tentunya harus ada perpustakaan di luar sana yang cocok dengan sweet-spot perpustakaan jaringan async yang disederhanakan!

[edit: terima kasih banyak kepada intgr untuk penunjuknya ke halaman ini . Jika Anda menggulir ke bawah Anda akan melihat ada daftar proyek yang sangat bagus yang bertujuan untuk menangani tugas ini dengan satu atau lain cara. Tampaknya sebenarnya hal-hal telah benar-benar bergerak sejak dimulainya Twisted: orang sekarang tampaknya lebih menyukai solusi berbasis rutinitas daripada yang berorientasi pada reaktor / panggilan balik tradisional. Manfaat dari pendekatan ini adalah kode yang lebih jelas: saya pasti pernah menemukan di masa lalu, terutama ketika bekerja dengan boost.asiodalam C ++ bahwa kode berbasis panggilan balik dapat menyebabkan desain yang sulit diikuti dan relatif tidak jelas bagi mata yang tidak terlatih. Menggunakan co-rutin memungkinkan Anda untuk menulis kode yang terlihat sedikit lebih sinkron. Saya kira sekarang tugas saya adalah menentukan salah satu dari sekian banyak perpustakaan yang saya suka tampilan dan mencobanya! Senang saya bertanya sekarang ...]

[sunting: mungkin menarik bagi siapa saja yang mengikuti atau menemukan masalah ini atau peduli dengan topik ini dalam arti apa pun: Saya menemukan artikel yang sangat bagus tentang kondisi terkini dari alat yang tersedia untuk pekerjaan ini]

jkp
sumber
14
Python adalah multithreaded, hanya saja tidak memungkinkan dua utas untuk menjalankan kode Python secara bersamaan.
intgr
86
Saya telah belajar lebih banyak dari pertanyaan Anda daripada dari jawaban untuk itu.
Denis Otkidach
2
@Denis: heh, terima kasih kurasa! Ada beberapa petunjuk bagus dalam jawaban juga, khususnya intgr's. Aku tahu tentang banyak pilihan di luar sana dan saya tidak hanya ingin jawaban dikemas dengan orang-orang jadi saya pikir saya akan pergi ke kesulitan mengeja apa yang saya tahu :)
jkp
5
> orang sekarang tampaknya lebih menyukai solusi berbasis rutin daripada daripada reaktor tradisional / berorientasi panggilan balik. Ini bukan perbandingan yang masuk akal. "solusi berbasis co-rutin" dan "berorientasi reaktor" adalah solusi orthogonal. (Mengabaikan fakta bahwa Python tidak memiliki coroutine) Lihatlah inlineCallbacks Twisted untuk melihat bagaimana Anda dapat memiliki gaya pemrograman yang tampaknya Anda sukai dengan lapisan jaringan yang kuat dan matang yang tidak akan membuat Anda terpapar keanehan platform yang kompleks.
Jean-Paul Calderone
2
Beberapa poin untuk ditambahkan: 1. Tornado berjalan sangat baik di Windows. Itu hanya tidak sebagai pemain dan scalable karena digunakan selectuntuk I / O multiplexing. Tetapi Anda harus bisa mendapatkan kinerja yang layak dengan tornado-pyuv . 2. Sekarang ada asyncio di Python 3.3+ dan trollius backport- nya yang memungkinkan untuk menjalankan aplikasi Tornado apa pun di loop acara (Twisted akan segera didukung).
schlamar

Jawaban:

28

Saya menyukai modul Python concurrence yang bergantung pada microthreads Python Stackless atau Greenlets untuk threading ringan. Semua I / O jaringan pemblokiran secara transparan dibuat asinkron melalui satu libeventloop, sehingga harus hampir seefisien server asinkron yang sebenarnya.

Saya kira ini mirip dengan Eventlet dengan cara ini.

Kelemahannya adalah API-nya sangat berbeda dengan Python sockets/ threadingmodul; Anda perlu menulis ulang sedikit aplikasi Anda (atau menulis lapisan shim kompatibilitas)

Sunting: Tampaknya ada juga cogen , yang serupa, tetapi menggunakan generator Python 2.5 yang disempurnakan untuk coroutine-nya, bukan Greenlets. Ini membuatnya lebih portabel daripada persetujuan dan alternatif lainnya. Jaringan I / O dilakukan secara langsung dengan epoll / kqueue / iocp.

Intgr
sumber
@intgr: tautan bagus. Saya pernah melihat keduanya sebelumnya, itu adalah hal-hal yang saya harap bisa lenyap. +1
jkp
3
Sepertinya persetujuan adalah proyek mati dengan pembaruan terakhir mereka empat tahun lalu.
Gewthen
proyek sudah mati, begitu pula Hyves!
Bahadir Cambel
1
Banyak yang telah terjadi sejak Python 2.5. asyncio dalam Python 3.5 sangat bagus.
Joseph Sheedy
99

Twisted itu rumit, Anda benar tentang itu. Twisted tidak kembung.

Jika Anda melihat di sini: http://twistedmatrix.com/trac/browser/trunk/twisted Anda akan menemukan paket terorganisir, komprehensif, dan sangat teruji dari banyak protokol internet, serta kode pembantu untuk menulis dan menyebarkan aplikasi jaringan yang sangat canggih. Saya tidak akan bingung mengasapi dengan kelengkapan.

Sudah diketahui umum bahwa dokumentasi Twisted bukan yang paling ramah pengguna dari pandangan pertama, dan saya percaya ini memalingkan banyak orang. Tapi Twisted luar biasa (IMHO) jika Anda memasukkan waktu. Saya lakukan dan terbukti sepadan, dan saya akan merekomendasikan kepada orang lain untuk mencoba yang sama.

clemesha
sumber
4
@clemesha: mungkin Anda benar, dan tidak dibebani, tetapi rasanya ada sedikit terlalu banyak untuk membuat kepala saya melakukan sesuatu yang sederhana. Saya mengerti pemrograman async, saya telah bekerja di C ++ dengan boost :: asio jadi konsepnya bukan hal baru, tetapi semua gumph yang melakukan hal-hal memutar: itu adalah dunia yang sama sekali baru, seperti halnya django untuk hal-hal web. Sekali lagi ketika saya melakukan hal-hal web saya bekerja dengan kode WSGI ringan dan hanya menyambungkan apa yang saya butuhkan. Kuda untuk kursus saya kira.
jkp
7
@clemesha: erm, saya mengambil risiko hari ini untuk melihat: memutar beratnya di 20MB! Bahkan intinya 12MB .... jika itu tidak kembung, saya tidak yakin apa itu.
jkp
29
Twisted APIs dasar cukup kecil (reaktor, ditangguhkan, protokol). Sebagian besar kode Twisted adalah implementasi protokol async menggunakan dasar-dasar itu. "Gembung" bukan kata sifat yang berguna di sini (atau memang dalam banyak kasus). Ukuran twisted masuk akal untuk jumlah barang yang dikerjakannya.
daf
56

gevent adalah eventlet dibersihkan .

API-bijaksana mengikuti konvensi yang sama seperti perpustakaan standar (khususnya, modul threading dan multiprocessing) di mana masuk akal. Jadi, Anda memiliki hal-hal yang akrab seperti Antrian dan Acara untuk dikerjakan.

Ini hanya mendukung libevent ( pembaruan: libev sejak 1.0 ) sebagai implementasi reaktor tetapi mengambil keuntungan penuh darinya, menampilkan server WSGI cepat berdasarkan libevent-http dan menyelesaikan permintaan DNS melalui libevent-dns sebagai ganti menggunakan kumpulan benang seperti kebanyakan perpustakaan lainnya melakukan. ( pembaruan: karena 1.0 c-ares digunakan untuk membuat permintaan DNS async; threadpool juga merupakan pilihan.)

Seperti eventlet, itu membuat panggilan balik dan tangguhan tidak perlu dengan menggunakan greenlets .

Lihatlah contoh-contohnya: unduhan bersamaan dari beberapa url , webchat polling panjang .

Denis Bilenko
sumber
4
Saya akan gevent kedua - Setelah meninjau banyak solusi, gevent bekerja sangat baik untuk saya. Itu memungkinkan saya untuk mempertahankan bagian yang lebih baik dari program saya yang ada, dan perubahan yang diperlukan itu sepele - Terbaik dari semua, jika kode perlu dipertahankan dalam 3, 4, 5, ... tahun waktu, masih membuat masuk akal bagi siapa pun yang tidak terbiasa dengan gevent, showstopper terbesar untuk Twisted adalah kurva belajar yang kuat, ini menyebabkan masalah tidak hanya ketika menerapkan, tetapi juga lebih jauh ke depan selama pemeliharaan ...
Martin Tournoij
27

Sebuah perbandingan yang sangat menarik dari kerangka kerja tersebut disusun oleh Nicholas Piël di blog-nya: layak dibaca!

jkp
sumber
2
Sementara saya setuju bahwa artikel adalah bacaan yang menarik, saya pikir bermanfaat untuk mempertimbangkan validitas tolok ukur yang disajikan. Lihat komentar di sini: reddit.com/r/programming/comments/ahepg/…
clemesha
1
@clemesha, sementara titik di halaman reddit itu patut dicatat, benchmark dilakukan pada mesin dual core dan kemungkinan tidak menderita cacat fatal yang dijelaskan. Saya kira itu mungkin baik klien dan server berjalan pada inti yang sama, tetapi sepertinya tidak mungkin.
Peter Hansen
15

Tak satu pun dari solusi ini akan menghindari fakta bahwa GIL mencegah paralelisme CPU - mereka hanya cara yang lebih baik untuk mendapatkan paralelisme IO yang sudah Anda miliki dengan utas. Jika Anda pikir Anda bisa melakukan IO yang lebih baik, tentu saja lakukan salah satunya, tetapi jika hambatan Anda dalam memproses hasilnya, tidak ada yang akan membantu di sini kecuali untuk modul multiprosesing.

Adam Hupp
sumber
Apa yang salah dengan menggunakan banyak proses?
Emil Ivanov
3
Tidak ada sama sekali, maka saran untuk menggunakan modul multiprocessing.
Adam Hupp
11

Saya tidak akan menyebut Twisted bengkak, tetapi sulit untuk membungkus kepala Anda. Saya menghindari benar-benar menyelesaikan belajar cukup lama karena saya selalu menginginkan sesuatu yang sedikit lebih mudah untuk 'tugas-tugas kecil'.

Namun, sekarang saya telah bekerja dengannya lagi saya harus mengatakan memiliki semua baterai sudah SANGAT bagus.

Semua pustaka async lain yang telah saya kerjakan akhirnya jauh kurang matang daripada yang muncul. Loop acara Twisted solid.

Saya tidak yakin bagaimana cara menyelesaikan kurva pembelajaran Twisted yang curam. Mungkin membantu jika seseorang akan membayarnya dan membersihkan beberapa hal, seperti menghapus semua kesalahan kompatibilitas mundur dan proyek mati. Tapi kurasa itulah sifat dari perangkat lunak yang matang.

rhettg
sumber
Jika Anda pernah melihat bagaimana reaktor gtk diimplementasikan di Windows (polling hardcore setiap 10ms: twistedmatrix.com/trac/browser/trunk/twisted/internet/… ), Anda tidak akan menyebut "dewasa" ...
schlamar
2
Hai @ schlamar. Hack jahat ini diimplementasikan sebagai solusi untuk beberapa bug yang cukup serius di GTK +, pada hari ketika ada jauh lebih sedikit kekhawatiran tentang efisiensi daya :). Tapi, keindahan Twisted adalah kita dapat memiliki bug ini sekali , memperbaikinya dalam kerangka, dan pengguna kita tidak perlu khawatir tentang hal itu. Apakah Anda ingin berkontribusi perbaikan yang mengatasi masalah ini dan menghilangkan (usang dan kemudian menghapus) PortableGtkReactor?
Glyph
1
@Glyph Saya menambahkan saran bermanfaat pada twistedmatrix.com/trac/ticket/4744#comment .: jika orang lain ingin mengatasi masalah ini, karena beberapa masalah tesis masih ada. BTW, Anda bisa memecahkan ini jauh lebih efisien dengan menjadwalkan panggilan balik antara dua loop acara.
schlamar
7

Kamaelia belum disebutkan. Model konkurensi didasarkan pada komponen kabel bersama dengan pesan yang lewat di antara kotak masuk dan kotak keluar. Berikut ini gambaran singkatnya.

Steven Kryskalla
sumber
5
Saya menggunakan kamaelia untuk sebuah aplikasi - itu sangat menyakitkan. IMHO ada pilihan lain yang lebih baik untuk concurrenct dengan python (sebagian besar disebutkan di atas)
Ben Ford
7

Saya sudah mulai menggunakan twisted untuk beberapa hal. Keindahannya hampir karena ia "kembung." Ada konektor untuk hampir semua protokol utama di luar sana. Anda dapat memiliki bot jabber yang akan mengambil perintah dan memposting ke server irc, mengirim email kepada seseorang, menjalankan perintah, membaca dari server NNTP, dan memantau halaman web untuk perubahan. Berita buruknya adalah ia dapat melakukan semua itu dan dapat membuat hal-hal yang terlalu rumit untuk tugas-tugas sederhana seperti yang dijelaskan OP. Keuntungan dari python adalah Anda hanya memasukkan apa yang Anda butuhkan. Jadi, sementara unduhannya mungkin 20mb, Anda hanya dapat memasukkan 2mb perpustakaan (yang masih banyak). Keluhan terbesar saya dengan twisted adalah meskipun mereka menyertakan contoh, apa pun di luar server tcp dasar yang Anda miliki sendiri.

Meskipun bukan solusi python, saya telah melihat node.js mendapatkan traksi lebih banyak akhir-akhir ini. Sebenarnya saya sudah mempertimbangkan untuk mencari proyek yang lebih kecil tapi saya merasa ngeri ketika mendengar javascript :)

getaran
sumber
Saya penggemar berat Python. - Lihat “Javascript - Bagian yang bagus” dari Douglas Crockford (3, 4 video). Dan intip di CoffeeScript. Ternyata JS memiliki hal-hal yang seharusnya dimiliki Python, kecuali Sintaksnya, haha. CS mencoba mengurangi itu, tetapi sedikit canggung tentang itu ...
Robert Siemer
4

Ada buku bagus tentang masalah ini: "Twisted Network Programming Essentials", oleh Abe Fettig. Contoh-contoh menunjukkan bagaimana menulis kode yang sangat Pythonic, dan bagi saya pribadi, jangan menganggap saya berdasarkan pada kerangka yang membengkak. Lihatlah solusi dalam buku ini, jika tidak bersih, maka saya tidak tahu apa artinya bersih.

Satu-satunya teka-teki saya adalah sama dengan yang saya miliki dengan kerangka kerja lain, seperti Ruby. Saya khawatir, apakah itu meningkat? Saya akan benci untuk melakukan klien untuk kerangka kerja yang akan memiliki masalah skalabilitas.

mrsmoothie
sumber
4

Whizzer adalah kerangka soket asinkron kecil yang menggunakan pyev. Sangat cepat, terutama karena pyev. Ia mencoba untuk menyediakan antarmuka yang sama seperti memutar dengan beberapa perubahan kecil.

bfrog
sumber
2

Coba juga Syncless . Ini berbasis coroutine (jadi mirip dengan Concurrence, Eventlet dan gevent). Ini mengimplementasikan penggantian non-pemblokiran drop-in untuk socket.socket, socket.gethostbyname (dll.), Ssl.SSLSocket, time.sleep dan select.select. Itu cepat. Perlu Stackless Python dan libevent. Ini berisi ekstensi Python wajib yang ditulis dalam C (Pyrex / Cython).

Poin
sumber
2

Saya Mengonfirmasi kebaikan sinkronisasi . Itu dapat menggunakan libev (libevent versi yang lebih baru, lebih bersih, dan lebih baik). Beberapa waktu yang lalu ia tidak memiliki dukungan sebanyak yang dimiliki libevent, tetapi sekarang proses pengembangannya berjalan lebih jauh dan sangat berguna.

Robert Zaremba
sumber
1

Jika Anda hanya ingin Perpustakaan Permintaan HTTP Sederhana, ringan maka saya menemukan Unirest sangat bagus

ejectamenta
sumber
0

Anda dipersilakan untuk melihat PyWorks, yang mengambil pendekatan yang sangat berbeda. Itu memungkinkan instance objek berjalan di utas mereka sendiri dan membuat panggilan fungsi ke objek itu async.

Biarkan saja sebuah kelas mewarisi dari Tugas alih-alih objek dan async, semua pemanggilan metode adalah Proxy. Nilai pengembalian (jika Anda membutuhkannya) adalah proxy Masa Depan.

res = obj.method( args )
# code continues here without waiting for method to finish
do_something_else( )
print "Result = %d" % res # Code will block here, if res not calculated yet

PyWorks dapat ditemukan di http://bitbucket.org/raindog/pyworks

renejsum
sumber
1
Meskipun ini menarik dan mungkin cocok untuk beberapa tugas, menggunakan utas untuk jaringan berkinerja buruk (terutama pada Python karena GIL). Dan ini persis pertanyaannya: kerangka kerja yang terjadi atau dengan multiprosesor. Jadi jawaban Anda jelas di luar jangkauan ...
schlamar