Eşzamanlılık ile başa çıkmak için Python'a sadık mı kalmalı mıyım?


31

Ben 10K var LOC yazılmış projeyi Django oldukça anlaşma ile Kereviz ( RabbitMQ gerekli asynchronicity ve arka plan işler için), ve sistemin parçaları içinde yeniden engelleyin yararı olacağını sonucuna vardık şey daha iyi eşzamanlılık için Django dışındaki . Sebepler:

  • İşaretlerin kullanımı ve değişken nesneler. Özellikle bir sinyal diğerini tetiklediğinde, ORM kullanarak onları Django'da kullanmak, örnekler değiştiğinde veya kaybolduğunda şaşırtıcı olabilir. İletilen verilerin işleyicide değişmediği bazı mesajlaşma yaklaşımlarını kullanmak istiyorum ( eğer doğru yaparsam Clojure'un yazma üzerine kopyalama yaklaşımı hoş görünüyor).
  • Sistemin parçaları web tabanlı değildir ve aynı anda görevleri gerçekleştirmek için daha iyi desteğe ihtiyaç duyarlar. Örneğin, sistem NFC etiketlerini okur ve bir LED birkaç saniye boyunca okunduğunda (Kereviz görevi), bir ses çalınır (diğer Kereviz görevi) ve veritabanı sorgulanır (diğer görev). Bu, bir Django yönetim komutu olarak uygulanır, ancak Django ve ORM'sinin doğaya göre senkronize olması ve hafızayı paylaşması sınırlıdır (daha fazla NFC okuyucusu eklemeyi düşünüyoruz ve Django + Kereviz yaklaşımının artık işe yarayacağını sanmıyorum. Mesaj iletme yeteneklerini daha iyi görmek istiyorum).

Erlang veya Clojure gibi bir dile gitmeye kıyasla Twisted veya Tornado gibi bir şey kullanmanın artıları ve eksileri nelerdir? Pratik faydalar ve zararlarla ilgileniyorum.

Sistemin bazı bölümlerinin başka bir dilde daha iyi olacağı sonucuna nasıl geldiniz? Performans sorunu mu yaşıyorsunuz? Bu sorunlar ne kadar şiddetli? Daha hızlı olabilirse, daha hızlı olması şart mıdır?

Örnek 1: Bir HTTP isteği dışındaki işyerinde Django:

  1. Bir NFC etiketi okunur.
  2. Veri tabanı (ve muhtemelen LDAP) sorgulanır ve veriler kullanılabilir olduğunda bir şey yapmak istiyoruz (kırmızı veya yeşil ışık, ses çalar). Bu, Django ORM kullanımını engeller, ancak mevcut kereviz işçileri olduğu sürece farketmez. Daha fazla istasyonda sorun olabilir.

Örnek 2: Django sinyallerini kullanarak “mesaj iletme”:

  1. Bir post_deleteolay işlenir, bu nedenle diğer nesneler değiştirilebilir veya silinebilir.
  2. Sonunda, bildirimler kullanıcılara gönderilmelidir. Burada, bildirim işleyicisine iletilen argümanların silinmiş veya silinecek nesnelerin kopyaları olsaydı ve işleyicide değişiklik yapmamasını garantilerse iyi olurdu. (ORM tarafından yönetilen nesnelerin elbette işleyicilere iletilmemesiyle manuel olarak yapılabilir.)


5
Kimse dil seçim sorularının konu dışı olduğunu söylemeden önce, bunun iyi şartlar olduğunu düşündüğümden beri bunun iyi olduğunu düşündüğümü söyleyeceğim. Umarım bazı detaylı karşılaştırmalar yapar.
Adam Lear

Bükülmüş eşzamanlı karşısındadır ! Olayla çalışan tek bir iş parçacıklı bir sunucudur, gerçek eşzamanlılığa ihtiyacınız olursa sizi hiçbir yere götürmez.

Yanıtlar:


35

Düşünceleri Açmak

Sistemin bazı bölümlerinin başka bir dilde daha iyi olacağı sonucuna nasıl geldiniz? Performans sorunu mu yaşıyorsunuz? Bu sorunlar ne kadar şiddetli? Daha hızlı olabilirse, daha hızlı olması şart mıdır?

Tek iş parçacıklı eşzamansız

Tek iş parçacıklı eşzamansızlık ve çok iş parçacığı eşzamanlılığının farklılıkları, artıları ve eksileri ile ilgili birçok soru ve başka web kaynakları bulunmaktadır. Node.js'in tek iş parçacıklı asenkron modelinin I / O ana tıkanıklık olduğunda nasıl bir performans gösterdiğini ve aynı anda servis verilen birçok istek olduğunu okumak ilginçtir .

Twisted, Tornado ve diğer asenkron modeller, tek bir dişlinin mükemmel bir şekilde kullanılmasını sağlıyor. Çok sayıda web programlaması çok fazla G / Ç'ye (ağ, veritabanı vb.) Sahip olduğu için, uzak çağrıları beklemek için harcanan zaman önemli ölçüde artar. Diğer veritabanı aramalarını başlatmak, sayfa oluşturmak ve veri üretmek gibi başka şeyler yapmak için harcanan zaman budur. Bu tek ipliğin kullanımı son derece yüksektir.

Tek iş parçacıklı eşzamansızlığın en büyük yararlarından biri, daha az bellek kullanmasıdır. Çok iş parçacıklı yürütme, her iş parçacığı, belirli bir miktarda ayrılmış bellek gerektirir. Diş sayısı arttıkça, sadece dişlerin var olması için gereken hafıza miktarı da artar. Bellek sonlu olduğundan, herhangi bir zamanda oluşturulabilecek iplik sayısında sınırlar olduğu anlamına gelir.


Örnek

Bir web sunucusu durumunda, her bir talebe kendi başlığına verilir gibi davran. Her iş parçacığı için 1 MB bellek gerektiğini ve web sunucusunun 2GB RAM’e sahip olduğunu söyleyin. Bu web sunucusu herhangi bir zamanda (yaklaşık olarak) 2000 isteğini herhangi bir zamanda işleme koyabilecek ve daha fazla işlem yapabilecek kadar bellek kalmayacaktı.

Yükünüz bundan daha yüksekse, istekler çok uzun sürecektir (daha eski isteklerin tamamlanmasını beklerken) veya olası eşzamanlı istek sayısını artırmak için kümeye daha fazla sunucu atmanız gerekecek .


Çok iş parçacıklı eşzamanlılık

Çok iş parçacığı eşzamanlılık yerine, aynı anda birkaç görevi yürütmeye dayanır. Bu, bir iş parçacığı geri dönmek için bir veritabanı çağrısında bekleyen engellenirse, diğer isteklerin aynı anda işlenebileceği anlamına gelir. İplik kullanımı daha düşüktür, ancak yürütülen iplik sayısı çok daha fazladır.

Çok iş parçacıklı kod da nedeni çok daha zordur. Kilitleme, senkronizasyon ve diğer eğlenceli eşzamanlılık sorunları ile ilgili sorunlar var. Tek iş parçacıklı asenkronizasyon aynı sorunlardan muzdarip değildir.

Ancak çoklu iş parçacığı kodu CPU yoğun görevler için çok daha başarılı . Bir iş parçacığının “verimi” (normal olarak engelleyebilecek bir ağ araması gibi) için bir fırsat yoksa, tek iş parçacıklı bir model hiçbir şekilde eşzamanlılığa sahip olmaz.

Her ikisi de bir arada olabilir

Tabi ikisi arasında örtüşme var; karşılıklı olarak dışlayıcı değillerdir. Örneğin, çoklu iş parçacığı kodu, her iş parçacığını daha iyi kullanmak için engelleyici olmayan bir şekilde yazılabilir.


Alt çizgi

Dikkate alınması gereken başka birçok konu var, ancak bunun gibi ikisini düşünmeyi seviyorum:

  • Programınız G / Ç'ye bağlıysa , tek iş parçacıklı asenkronizasyon muhtemelen oldukça iyi çalışacaktır.
  • Programınız CPU'ya bağlıysa , o zaman çok parçalı bir sistem muhtemelen en iyisi olacaktır.

Sizin durumunuzda, ne tür asenkronize çalışmanın tamamlandığını ve bu görevlerin ne sıklıkla ortaya çıktığını belirlemeniz gerekir.

  • Her talepte ortaya çıkıyor mu? Öyleyse, istek sayısı arttıkça bellek muhtemelen bir sorun haline gelecektir.
  • Bu görevler sipariş edildi mi? Öyleyse, birden fazla iş parçacığı kullanıyorsanız senkronizasyonu düşünmeniz gerekir.
  • Bu görevler CPU yoğun mu? Eğer öyleyse, tek bir diş yüke ayak uydurabiliyor mu?

Basit bir cevap yok. Kullanım durumunuzun ne olduğunu göz önünde bulundurmalı ve buna göre tasarlamalısınız. Bazen eşzamansız tek iş parçacıklı bir model daha iyidir. Diğer zamanlarda, büyük paralel işleme elde etmek için çok sayıda diş kullanılması gerekir.

Diğer Hususlar

Seçtiğiniz eşzamanlılık modelinden ziyade, göz önünde bulundurmanız gereken başka konular da var. Erlang veya Clojure'u tanıyor musunuz? Uygulamanızın performansını artırabilmeniz için bu dillerden birinde güvenli çoklu iş parçacığı kodu yazabileceğinizi düşünüyor musunuz? Bu dillerden birinde hız kazanmanız uzun zaman alacak mı ve öğrendiğiniz dil gelecekte size fayda sağlayacak mı?

Bu iki sistem arasındaki iletişim ile ilgili zorluklara ne dersiniz? İki ayrı sistemi paralel olarak tutmak aşırı derecede karmaşık olacak mı? Erlang sistemi Django'dan nasıl görev alacak? Erlang bu sonuçları Django'ya nasıl iletecek? Performans, eklenen karmaşıklığın buna değeceği bir problem mi?


Son düşünceler

Django'yu her zaman yeterince hızlı buldum ve çok yoğun trafik çeken siteler tarafından kullanılıyor. Eşzamanlı istek sayısını ve yanıt süresini artırmak için yapabileceğiniz çeşitli performans optimizasyonları vardır. Kuşkusuz, şu ana kadar Celery ile hiçbir şey yapmadım, bu yüzden normal performans optimizasyonları muhtemelen bu asenkron işlerde karşılaşabileceğiniz sorunları çözmeyecektir.

Tabii ki, her zaman soruna daha fazla donanım atma önerisi vardır. Yeni bir sunucu sağlama maliyeti, tamamen yeni bir alt sistemin geliştirme ve bakım maliyetinden daha mı ucuz?

Bu noktada çok fazla soru sordum, ama niyetim buydu. Cevap, analiz olmadan ve daha fazla ayrıntı olmadan kolay olmayacak. Sorunları analiz edebilmek, sorulması gereken soruları bilmekten kaynaklanıyor.

İçimdeki hisler başka bir dilde tekrar yazmanın gereksiz olduğunu söylüyor. Karmaşıklık ve maliyet muhtemelen çok büyük olacak.


Düzenle

İzlemeye Tepki

Takipleriniz bazı ilginç kullanım durumları sunar.


1. Django HTTP istekleri dışında çalışıyor

İlk örneğiniz NFC etiketlerini okuduktan sonra veritabanını sorguladı. Bu bölümü başka bir dilde yazmanın sizin için bu kadar faydalı olacağını sanmıyorum, çünkü sadece veritabanını veya bir LDAP sunucusunu sorgulamak ağ giriş / çıkış (ve potansiyel olarak veritabanı performansı) tarafından bağlanacak. Öte yandan, her yönetim komutu kendi işlemi olarak çalıştırılacağından, eşzamanlı isteklerin sayısı sunucunun kendisi tarafından sınırlandırılacaktır. Halen çalışan bir işleme mesaj gönderemediğiniz için performansı etkileyen kurulum ve ayırma süresi olacaktır. Bununla birlikte, her biri yalıtılmış bir işlem olacağından, aynı anda birden fazla istek gönderebileceksiniz.

Bu durumda, araştırabileceğiniz iki yol görüyorum:

  1. Veritabanınızın bağlantı havuzuyla aynı anda birden fazla sorguyu işleme yeteneğine sahip olduğundan emin olun. (Örneğin, Oracle, Django’yu buna göre yapılandırmanızı gerektirir 'OPTIONS': {'threaded':True}.) Veri tabanı düzeyinde veya Django düzeyinde kendi veritabanınız için ince ayar yapabileceğiniz benzer yapılandırma seçenekleri olabilir. Veritabanınızın sorgularını hangi dilde yazdığınız önemli değildir, LED'leri yakmadan önce bu verilerin geri dönmesini beklemeniz gerekecektir. Sorgulama kodunun performans olabilir (gerçi bir fark yaratmak ve Django ORM ışık hızında değil ama genelde yeterince hızlı).
  2. Kurulum / ayırma süresini en aza indirin. Sürekli çalışan bir işlem yapın ve mesaj gönderin. (Hatalıysam beni düzelt, ancak asıl sorunuzun odaklandığı şey budur.) Bu işlemin Python / Django'da mı yoksa başka bir dilde / çerçevede mi yazıldığını. Yönetim komutlarını çok sık kullanma fikrinden hoşlanmıyorum. Sürekli çalışan, NFC okuyucularından gelen mesajları ileti kuyruğuna iten, kerevizin daha sonra Django'ya okuduğu ve ilettiği küçük bir kod parçası olması mümkün müdür? Python'da yazılsa bile (ancak Django! Değil) küçük bir programın kurulması ve parçalanması, bir Django programının başlatılması ve durdurulmasından (tüm alt sistemleriyle) daha iyi olmalıdır.

Django için hangi web sunucusunu kullandığınızdan emin değilim. mod_wsgiApache için, hizmetin talep ettiği işlemler içindeki işlemlerin ve iş parçacıklarının sayısını yapılandırmanıza olanak sağlar. Servis verilebilir istek sayısını optimize etmek için web sunucunuzun ilgili konfigürasyonunu değiştirdiğinizden emin olun.


2. Django sinyalleriyle “mesaj iletme”

İkinci kullanım durumunuz da oldukça ilginç; Bunun için cevapları alıp almadığımdan emin değilim. Model örneklerini siliyorsanız ve daha sonra üzerinde çalışmak istiyorsanız, bunları seri hale getirmek JSON.dumpsve seri hale getirmek mümkün olabilir JSON.loads. Nesne grafiğini daha sonra tamamen yeniden oluşturmak mümkün olmaz (ilgili modellerin sorgulanması), çünkü ilgili alanlar veritabanından tembel olarak yüklenir ve bu bağlantı artık varolmaz.

Diğer seçenek, bir şekilde silmek için bir nesneyi işaretlemek ve yalnızca istek / yanıt döngüsünün sonunda (tüm sinyallerin servisi yapıldıktan sonra) silmek olacaktır. Güvenmek yerine bunu uygulamak için özel bir sinyal gerektirebilir post_delete.


1
Çok fazla FUD ve kilitleme ve Erlang'la ilgili olmayan diğer şeylerle ilgili şüpheler, listelediğiniz geleneksel paylaşılan durum sorunlarından hiçbiri, özellikle durumu paylaşmamak için tasarlanmış bir dil ve çalışma zamanı ile ilgili düşünceler değildir. Erlang, çok az ramda on binlerce gizli işlemi gerçekleştirebilir, bellek baskısı da sorun değil.

@ Jarrod, ben şahsen Erlang'ı tanımıyorum. Aksi takdirde bahsettiğim hemen hemen her şey alakalı. Maliyet, karmaşıklık ve mevcut araçların doğru bir şekilde kullanılıp kullanılmadığı.
Josh Smeaton


Bu ^ ^ 'ı okumayı gerçekten sevdiğim epik cevabın türü. +1, iyi iş!
Laurent Bourgault-Roy

Ayrıca eğer DJango şablonlarınız varsa, Erlydtl
Zachary K ile

8

Büyük bir ABD ISS'si için çok karmaşık, ölçeklenebilir bir gelişme yaptım . Twisted sunucusunu kullanarak bazı ciddi tranasaction numaraları yaptık ve Python / Twisted 'un CPU'ya bağlı herhangi bir şeyi ölçeklendirmesi karmaşık bir kabustu . G / Ç bağlaması bir sorun değildir, ancak CPU bağlaması imkansızdı. Sistemleri hızlı bir şekilde bir araya getirebiliriz, ancak milyonlarca eşzamanlı kullanıcıya ölçeklendirilmelerini sağlamak, eğer CPU tarafından bağlı olsaydı, yapılandırma ve karmaşıklığın bir kabusuydu.

Bu konuda bir blog yazısı yazdım, Python / Twisted VS Erlang / OTP .

TLDR; Erlang kazandı.


4

Twisted ile ilgili (yaklaşık beş yıldır sevdiğim ve kullandığım) pratik sorunlar :

  1. Belgeler arzulanan bir şey bırakır ve model yine de öğrenmek için oldukça karmaşıktır. Diğer Python programcılarının Twisted koduyla çalışmasını zor buluyorum.
  2. Ben engelleme dosya G / Ç ve iyi erişim engelleme API eksikliği için veritabanı erişimi kullanarak sona erdi. Bu gerçekten performansa zarar verebilir.
  3. Twisted kullanarak büyük bir topluluk ve sağlıklı bir topluluk gibi görünmüyor; Mesela Node.js , özellikle web arka uç programlaması için çok daha aktif bir gelişime sahiptir.
  4. Hala Python ve en azından CPython etrafındaki en hızlı şey değil.

CoffeeScript ile Node.js kullanarak biraz iş yaptım ve eşzamanlı performans sizin endişeniz ise, o zaman bu sıçramaya değer olabilir.

Müşterileri örnekler arasında yaymak için bazı düzenlemelerle birden fazla Django örneği çalıştırmayı düşündünüz mü ?


1
Python belgeleri genel olarak arzulanan bir şey bırakır: / (Çok kötü olduğunu söylememek , ama popüler olan bir dil için daha iyi olmasını bekleyeceği bir dil için).
Rook

3
Python belgelerini ve özellikle de Django belgelerini, herhangi bir dil için en iyi belgelerin bazıları olarak buluyorum. Pek çok üçüncü taraf kütüphanesi, arzulanan bir şeyi bırakır.
Josh Smeaton,

1

Başka bir dile geçmeyi düşünmeden önce aşağıdakileri önereceğim.

  1. Sayfa hataları, bağlam anahtarları ve sistem çağrısı beklemeleri gibi sistem olaylarını kaydetmek için LTTng kullanın .
  2. C kitaplığını kullanmak için çok zaman harcadığı her yerde dönüştürme yapın ve istediğiniz selectG / Ç için iyi olan istediğiniz herhangi bir tasarım desenini (çoklu iş parçacığı, sinyal olayı tabanlı, geri çağırma veya geleneksel Unix ) kullanın.

Uygulama performansta önceliğe sahip olduğunda Python'da iş parçacığı kullanmam. Yazılımın yeniden kullanımı, Django ile bağlantı , performans, geliştirme kolaylığı vb. Gibi birçok sorunu çözebilen yukarıdaki seçeneği tercih ediyorum .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.