Haruskah saya bertahan atau mengabaikan Python untuk berurusan dengan konkurensi?


31

Saya memiliki proyek 10K LOC yang ditulis dalam bahasa Django dengan banyak seledri ( RabbitMQ ) untuk pekerjaan asinkronik dan latar belakang di mana diperlukan, dan sampai pada kesimpulan bahwa bagian-bagian dari sistem akan mendapat manfaat dari ditulis ulang pada sesuatu selain Django untuk konkurensi yang lebih baik . Alasannya termasuk:

  • Penanganan sinyal dan objek yang bisa berubah. Terutama ketika satu sinyal memicu yang lain, menangani mereka di Django menggunakan ORM bisa mengejutkan ketika instance berubah atau menghilang. Saya ingin menggunakan beberapa pendekatan pengiriman pesan di mana data yang dikirimkan tidak berubah dalam handler ( pendekatan copy-on-write Clojure tampak bagus, jika saya melakukannya dengan benar).
  • Bagian dari sistem tidak berbasis web, dan membutuhkan dukungan yang lebih baik untuk melakukan tugas secara bersamaan. Misalnya, sistem membaca tag NFC , dan ketika seseorang membaca LED menyala selama beberapa detik (tugas Seledri), suara dimainkan (tugas Seledri lainnya), dan basis data dipertanyakan (tugas lain). Ini diimplementasikan sebagai perintah manajemen Django, tetapi Django dan ORM-nya pada dasarnya bersifat sinkron dan berbagi memori terbatas (kami berpikir untuk menambah lebih banyak pembaca NFC, dan saya tidak berpikir bahwa pendekatan Django + Seledri akan bekerja lebih lama, Saya ingin melihat kemampuan lewat pesan yang lebih baik).

Apa pro dan kontra menggunakan sesuatu seperti Twisted atau Tornado dibandingkan dengan menggunakan bahasa seperti Erlang atau Clojure ? Saya tertarik pada manfaat dan kerugian praktis.

Bagaimana Anda sampai pada kesimpulan bahwa beberapa bagian sistem akan lebih baik dalam bahasa lain? Apakah Anda mengalami masalah kinerja? Seberapa parah masalah itu? Jika itu bisa lebih cepat, apakah penting bahwa itu lebih cepat?

Contoh 1: Django sedang bekerja di luar permintaan HTTP:

  1. Tag NFC dibaca.
  2. Basis data (dan mungkin LDAP) dipertanyakan, dan kami ingin melakukan sesuatu ketika data tersedia (lampu merah atau hijau, putar suara). Ini blok menggunakan Django ORM, tetapi selama ada pekerja Seledri yang tersedia itu tidak masalah. Mungkin ada masalah dengan lebih banyak stasiun.

Contoh 2: "message-passing" menggunakan sinyal Django:

  1. Suatu post_deleteperistiwa ditangani, objek lain dapat diubah atau dihapus karena ini.
  2. Pada akhirnya, pemberitahuan harus dikirim ke pengguna. Di sini, alangkah baiknya jika argumen yang diteruskan ke handler notifikasi adalah salinan objek yang dihapus atau yang akan dihapus dan dijamin tidak akan berubah pada handler. (Itu bisa dilakukan secara manual hanya dengan tidak melewatkan objek yang dikelola oleh ORM ke penangan, tentu saja.)

Saya pikir jawaban yang lebih baik akan terjadi jika Anda menjelaskan lebih lanjut tentang mengapa Anda sampai pada kesimpulan
Winston Ewert

5
Sebelum ada yang mengatakan bahwa pertanyaan pilihan bahasa di luar topik, saya akan berpura-pura mengatakan saya pikir ini baik-baik saja karena ini masalah praktis dengan persyaratan khusus. Saya harap ini menarik beberapa perbandingan terperinci.
Adam Lear

Twisted adalah kebalikan dari concurrent! Ini adalah server berulir tunggal yang dikendalikan oleh peristiwa, tidak akan membawa Anda ke mana pun jika Anda membutuhkan konkurensi sejati.

Jawaban:


35

Membuka Pikiran

Bagaimana Anda sampai pada kesimpulan bahwa beberapa bagian sistem akan lebih baik dalam bahasa lain? Apakah Anda mengalami masalah kinerja? Seberapa parah masalah itu? Jika itu bisa lebih cepat, apakah penting bahwa itu lebih cepat?

Sinkronisasi Satu-utas

Ada beberapa pertanyaan dan sumber daya web lain yang sudah berurusan dengan perbedaan, pro, dan kontra dari asynchrony single-thread vs multi-thread concurrency. Sangat menarik untuk membaca tentang bagaimana model asinkron single-thread Node.js tampil ketika I / O adalah hambatan utama, dan ada banyak permintaan yang dilayani sekaligus.

Twisted, Tornado, dan model asinkron lainnya memanfaatkan sekali utas. Karena banyak pemrograman web memiliki banyak I / O (jaringan, database, dll.), Waktu yang dihabiskan untuk menunggu panggilan jarak jauh bertambah secara signifikan. Itulah waktu yang dapat dihabiskan untuk melakukan hal-hal lain — seperti memulai panggilan basis data lain, merender halaman, dan menghasilkan data. Pemanfaatan single-thread itu sangat tinggi.

Salah satu manfaat terbesar dari asynchrony single-thread adalah menggunakan lebih sedikit memori. Dalam eksekusi multi-utas, setiap utas membutuhkan sejumlah memori yang dicadangkan. Saat jumlah utas meningkat, demikian juga jumlah memori yang diperlukan hanya agar utas ada. Karena memori terbatas, itu berarti ada batasan pada jumlah utas yang dapat dibuat pada satu waktu.


Contoh

Dalam kasus server web, berpura-pura setiap permintaan diberikan utasnya sendiri. Katakanlah 1MB memori diperlukan untuk setiap utas, dan server web memiliki 2GB RAM. Server web ini akan mampu memproses (kira-kira) 2000 permintaan kapan saja sebelum tidak ada cukup memori untuk diproses lagi.

Jika beban Anda secara signifikan lebih tinggi dari ini, permintaan akan memakan waktu yang sangat lama (ketika menunggu permintaan yang lebih lama selesai), atau Anda harus membuang lebih banyak server ke dalam kluster untuk memperluas jumlah permintaan bersamaan yang mungkin terjadi .


Multi-thread Concurrency

Konkurensi multi-utas alih-alih bergantung pada menjalankan beberapa tugas pada saat yang sama. Itu berarti bahwa jika utas diblokir menunggu panggilan database kembali, permintaan lain dapat diproses pada saat yang sama. Utilisasi thread lebih rendah, tetapi jumlah thread yang dieksekusi jauh lebih besar.

Kode multi-utas juga jauh lebih sulit untuk dipikirkan. Ada masalah dengan penguncian, sinkronisasi, dan masalah concurrency menyenangkan lainnya. Single-thread asynchrony tidak mengalami masalah yang sama.

Namun kode multi-thread jauh lebih berkinerja untuk tugas-tugas intensif CPU . Jika tidak ada peluang bagi utas untuk "menghasilkan" —seperti panggilan jaringan yang biasanya akan diblokir — model utas tunggal tidak akan memiliki konkurensi apa pun.

Keduanya hidup berdampingan

Tentu saja ada tumpang tindih antara keduanya; mereka tidak saling eksklusif. Misalnya, kode multi-utas dapat ditulis dengan cara non-pemblokiran, untuk memanfaatkan setiap utas dengan lebih baik.


Garis bawah

Ada banyak masalah lain yang perlu dipertimbangkan, tetapi saya suka memikirkan keduanya seperti ini:

  • Jika program Anda terikat I / O , maka asynchrony single-thread mungkin akan bekerja dengan baik.
  • Jika program Anda terikat CPU , maka sistem multi-thread mungkin akan lebih baik.

Dalam kasus khusus Anda, Anda perlu menentukan jenis pekerjaan asinkron yang sedang diselesaikan, dan seberapa sering tugas-tugas itu muncul.

  • Apakah itu terjadi pada setiap permintaan? Jika demikian, memori mungkin akan menjadi masalah karena jumlah permintaan meningkat.
  • Apakah tugas ini dipesan? Jika demikian, Anda harus mempertimbangkan sinkronisasi jika menggunakan banyak utas.
  • Apakah tugas-tugas ini intensif CPU? Jika demikian, apakah satu utas dapat mengimbangi beban?

Tidak ada jawaban sederhana. Anda harus mempertimbangkan apa yang Anda gunakan, dan desain yang sesuai. Terkadang model single-thread asynchronous lebih baik. Di lain waktu, menggunakan sejumlah utas untuk mencapai pemrosesan paralel masif diperlukan.

Pertimbangan Lainnya

Ada masalah lain yang perlu Anda pertimbangkan juga, bukan hanya model konkurensi yang Anda pilih. Apakah Anda tahu Erlang atau Clojure? Apakah Anda pikir Anda akan mampu menulis kode multi-thread yang aman dalam salah satu bahasa ini sehingga Anda meningkatkan kinerja aplikasi Anda? Apakah perlu waktu lama untuk mempercepat salah satu bahasa ini, dan apakah bahasa yang Anda pelajari akan menguntungkan Anda di masa depan?

Bagaimana dengan kesulitan yang terkait dengan komunikasi antara kedua sistem ini? Apakah akan terlalu rumit mempertahankan dua sistem terpisah secara paralel? Bagaimana sistem Erlang akan menerima tugas dari Django? Bagaimana Erlang akan mengkomunikasikan hasil itu kembali ke Django? Apakah kinerja cukup signifikan sebagai masalah sehingga kompleksitas yang ditambahkan sepadan?


Pikiran terakhir

Saya selalu menemukan Django cukup cepat, dan digunakan oleh beberapa situs yang sangat diperdagangkan. Ada beberapa optimisasi kinerja yang dapat Anda lakukan untuk meningkatkan jumlah permintaan dan waktu respons bersamaan. Memang, saya belum melakukan apa-apa dengan Celery sejauh ini, jadi optimisasi kinerja yang biasa mungkin tidak akan menyelesaikan masalah apa pun yang mungkin Anda alami dengan tugas-tugas tidak sinkron ini.

Tentu saja, selalu ada saran untuk melemparkan lebih banyak perangkat keras pada masalahnya. Apakah biaya penyediaan server baru lebih murah daripada biaya pengembangan dan pemeliharaan subsistem yang sama sekali baru?

Saya sudah mengajukan terlalu banyak pertanyaan pada saat ini, tapi itu maksud saya. Jawabannya tidak akan mudah tanpa analisis dan perincian lebih lanjut. Mampu menganalisis masalah datang ke mengetahui pertanyaan untuk diajukan, meskipun ... jadi mudah-mudahan saya telah membantu di depan

Perasaan saya mengatakan bahwa menulis ulang dalam bahasa lain tidak perlu. Kompleksitas dan biaya mungkin akan terlalu besar.


Edit

Tanggapan untuk Tindak Lanjut

Tindak lanjut Anda menyajikan beberapa kasus penggunaan yang sangat menarik.


1. Django bekerja di luar permintaan HTTP

Contoh pertama Anda melibatkan membaca tag NFC, lalu menanyakan database. Saya tidak berpikir bahwa menulis bagian ini dalam bahasa lain akan berguna bagi Anda, hanya karena permintaan basis data atau server LDAP akan terikat oleh jaringan I / O (dan berpotensi kinerja database). Di sisi lain, jumlah permintaan bersamaan akan terikat oleh server itu sendiri, karena setiap perintah manajemen akan dijalankan sebagai prosesnya sendiri. Akan ada waktu penyiapan dan penghancuran yang mempengaruhi kinerja, karena Anda tidak mengirim pesan ke proses yang sudah berjalan. Anda akan, bagaimanapun, dapat mengirim beberapa permintaan secara bersamaan, karena masing-masing akan menjadi proses yang terisolasi.

Untuk kasus ini, saya melihat dua jalan yang bisa Anda selidiki:

  1. Pastikan bahwa database Anda mampu menangani beberapa pertanyaan sekaligus dengan penyatuan koneksi. (Oracle, misalnya, mengharuskan Anda mengkonfigurasi Django yang sesuai 'OPTIONS': {'threaded':True}.) Mungkin ada opsi konfigurasi serupa di tingkat basis data atau tingkat Django yang dapat Anda atur untuk basis data Anda sendiri. Tidak peduli bahasa apa yang Anda gunakan untuk query database, Anda harus menunggu data ini kembali sebelum Anda dapat menyalakan LED. Kinerja kode kueri dapat membuat perbedaan, dan Django ORM tidak secepat kilat ( tapi , biasanya cukup cepat).
  2. Minimalkan waktu setup / teardown. Memiliki proses yang terus berjalan, dan mengirim pesan ke sana. (Koreksi saya jika saya salah, tetapi inilah yang menjadi fokus pertanyaan asli Anda.) Apakah proses ini ditulis dalam Python / Django atau bahasa / kerangka kerja lain dibahas di atas. Saya tidak suka gagasan sering menggunakan perintah manajemen. Mungkinkah ada sepotong kecil kode yang berjalan terus-menerus, yang mendorong pesan dari pembaca NFC ke antrian pesan, yang kemudian dibaca oleh Celery dan diteruskan ke Django? Setup dan teardown dari program kecil, bahkan jika itu ditulis dalam Python (tetapi bukan Django!), Harus lebih baik daripada memulai dan menghentikan program Django (dengan semua subsistemnya).

Saya tidak yakin server web apa yang Anda gunakan untuk Django. mod_wsgiuntuk Apache memungkinkan Anda mengonfigurasi jumlah proses dan utas dalam proses yang diminta layanan. Pastikan untuk mengubah konfigurasi server web Anda yang relevan untuk mengoptimalkan jumlah permintaan yang dapat diperbaiki.


2. "Pesan-lewat" dengan sinyal Django

Kasing kedua Anda juga cukup menarik; Saya tidak yakin apakah saya punya jawaban untuk itu. Jika Anda menghapus instance model, dan ingin mengoperasinya nanti, mungkin saja membuat serial JSON.dumpsdan kemudian membatalkan deserialisasi JSON.loads. Tidak mungkin untuk membuat kembali sepenuhnya objek grafik nanti (menanyakan model terkait), karena bidang terkait malas dimuat dari database, dan tautan itu tidak lagi ada.

Pilihan lain adalah entah bagaimana menandai objek untuk dihapus, dan hanya menghapusnya di akhir siklus permintaan / respons (setelah semua sinyal diservis). Mungkin memerlukan sinyal khusus untuk menerapkan ini, daripada mengandalkan post_delete.


1
banyak FUD dan keraguan tentang penguncian dan hal-hal lain yang tidak masalah dengan Erlang, tidak ada masalah negara berbagi tradisional Anda daftar pertimbangan dengan bahasa dan runtime yang dirancang khusus untuk tidak berbagi negara. Erlang dapat menangani puluhan ribu proses rahasia dalam ram yang sangat sedikit, tekanan memori juga tidak menjadi masalah.

@Jarrod, saya pribadi tidak tahu Erlang jadi saya akan menerima apa yang Anda katakan dalam hal itu. Kalau tidak, hampir semua yang saya sebutkan relevan. Biaya, kerumitan dan apakah alat saat ini digunakan dengan benar atau tidak.
Josh Smeaton


Ini adalah jenis jawaban epik yang sangat saya suka baca ^^. +1, kerja bagus!
Laurent Bourgault-Roy

Juga jika Anda memiliki template DJango, mereka dapat digunakan di erlang dengan Erlydtl
Zachary K

8

Saya melakukan beberapa pengembangan sangat skalabel sangat canggih untuk ISP AS utama . Kami melakukan beberapa nomor tranasaksi serius menggunakan server Twisted , dan itu adalah mimpi buruk kompleksitas untuk mendapatkan Python / Twisted untuk skala pada apa pun yang terikat CPU . I / O terikat bukan masalah, tetapi terikat CPU tidak mungkin. Kita dapat menyusun sistem dengan cepat, tetapi menjadikannya skala ke jutaan pengguna secara bersamaan adalah mimpi buruk konfigurasi dan kompleksitas jika diikat oleh CPU.

Saya menulis posting blog tentang hal itu, Python / Twisted VS Erlang / OTP .

TLDR; Erlang menang.


4

Masalah praktis dengan Twisted (yang saya sukai dan gunakan selama sekitar lima tahun):

  1. Dokumentasi meninggalkan sesuatu yang diinginkan, dan modelnya cukup rumit untuk dipelajari. Saya merasa sulit untuk mendapatkan programmer Python lain untuk bekerja pada kode Twisted.
  2. Saya akhirnya menggunakan file I / O pemblokiran dan akses basis data karena kurangnya API pemblokiran yang baik. Ini benar-benar dapat merusak kinerja.
  3. Tampaknya tidak ada komunitas besar dan komunitas sehat yang menggunakan Twisted; misalnya Node.js memiliki lebih banyak pengembangan aktif terutama untuk pemrograman back-end web.
  4. Itu masih Python, dan setidaknya CPython bukan yang tercepat di sekitar.

Saya telah melakukan sedikit pekerjaan menggunakan Node.js dengan CoffeeScript dan jika kinerja bersamaan menjadi perhatian Anda maka itu mungkin layak lompatan.

Sudahkah Anda mempertimbangkan untuk menjalankan beberapa instance Django dengan beberapa pengaturan untuk menyebarkan klien di antara instance?


1
Dokumentasi python dalam daun umumnya sesuatu yang diinginkan: / (Tidak mengatakan itu yang buruk, tapi untuk bahasa yang populer salah satu harapkan untuk itu untuk menjadi jauh lebih baik).
Benteng

3
Saya menemukan dokumentasi Python dan khususnya dokumentasi Django menjadi beberapa dokumen terbaik untuk bahasa apa pun. Banyak perpustakaan pihak ketiga meninggalkan sesuatu yang diinginkan.
Josh Smeaton

1

Saya akan menyarankan yang berikut sebelum Anda mempertimbangkan beralih ke bahasa lain.

  1. Gunakan LTTng untuk merekam peristiwa sistem seperti kesalahan halaman, sakelar konteks, dan menunggu panggilan sistem.
  2. Konversikan ke mana pun terlalu banyak waktu untuk menggunakan pustaka C, dan gunakan pola desain apa pun yang Anda suka (multi-threading, berbasis peristiwa sinyal, panggil kembali async, atau Unix tradisional select) yang bagus untuk I / O di sana.

Saya tidak akan menggunakan threading dengan Python setelah aplikasi memiliki prioritas dalam kinerja. Saya akan mengambil opsi di atas, yang dapat memecahkan banyak masalah seperti penggunaan kembali perangkat lunak, konektivitas dengan Django , kinerja, kemudahan pengembangan, dll.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.