Czysta, lekka alternatywa dla pokręconego Pythona? [Zamknięte]


222

(Dawno temu) napisałem pająka sieciowego, który wielowątkowo, aby umożliwić jednoczesne występowanie w tym samym czasie. Tak było w mojej młodości w Pythonie, w czasach, kiedy wiedziałem o GIL i związanych z nim nieszczęściach dla wielowątkowego kodu (IE, w większości przypadków rzeczy są po prostu serializowane!) ...

Chciałbym przerobić ten kod, aby był bardziej niezawodny i działał lepiej. Są w zasadzie dwa sposoby, aby to zrobić: mógłbym użyć nowego modułu wieloprocesowego w wersji 2.6+ lub wybrać jakiś model oparty na reaktorze / zdarzeniu. Wolę zrobić później, ponieważ jest to o wiele prostsze i mniej podatne na błędy.

Pytanie dotyczy więc tego, jakie ramy najlepiej pasowałyby do moich potrzeb. Poniżej znajduje się lista znanych mi opcji:

  • Twisted : Dziadek struktur reaktorów Pythona: wydaje się złożony i nieco rozdęty. Stroma krzywa uczenia się dla małego zadania.
  • Eventlet : Od facetów z Lindenlab . Ramy oparte na Greenlet ukierunkowane na tego rodzaju zadania. Spojrzałem jednak na kod i nie jest zbyt ładny: niezgodny z Pep8, rozrzucony wydrukami (dlaczego ludzie robią to w ramach !?), API wydaje się trochę niespójne.
  • PyEv : Niedojrzały, nie wydaje się, żeby ktoś go teraz używał, chociaż jest oparty na libevent, więc ma solidny backend.
  • asyncore : Z poziomu niskiego poziomu stdlib: über, wydaje się, że dużo pracy nóg wymaga tylko zrobienia czegoś z ziemi.
  • tornado : Chociaż jest to produkt zorientowany na serwer, przeznaczony do dynamicznych serwerów internetowych, zawiera on asynchronicznego klienta HTTP i prosty ioloop . Wygląda na to, że może to zrobić zadanie, ale nie do tego, do czego było przeznaczone. [edytuj: niestety nie działa w systemie Windows, co dla mnie się liczy - jest to wymagane, aby obsługiwać tę kiepską platformę]

Czy w ogóle coś mi umknęło? Z pewnością musi istnieć biblioteka, która pasuje do najprostszej biblioteki uproszczonej sieci asynchronicznej!

[edytuj: wielkie podziękowania dla intgr za jego wskaźnik do tej strony . Jeśli przewiniesz do dołu, zobaczysz naprawdę fajną listę projektów, które mają na celu sprostanie temu zadaniu w taki czy inny sposób. Wydaje się, że w rzeczywistości rzeczy potoczyły się od momentu powstania Twisted: ludzie wydają się teraz preferować rozwiązanie oparte na wspólnej procedurze , a nie tradycyjne rozwiązanie zorientowane na reaktor / oddzwanianie. Korzyści z tego podejścia są wyraźniejsze, bardziej bezpośredni kod: z pewnością znalazłem w przeszłości, szczególnie podczas pracy z boost.asiow C ++ ten kod oparty na wywołaniu zwrotnym może prowadzić do projektów trudnych do naśladowania i stosunkowo mało widocznych dla niewprawnego oka. Korzystanie z procedur wspólnych pozwala pisać kod, który wygląda trochę bardziej synchronicznie. Wydaje mi się, że teraz moim zadaniem jest ustalenie, której z tych wielu bibliotek lubię wyglądać i spróbować! Cieszę się, że zapytałem teraz ...]

[edytuj: być może zainteresuje każdego, kto podążył za tym pytaniem lub natknął się na to pytanie lub w jakikolwiek sposób troszczy się o ten temat: Znalazłem naprawdę świetny opis aktualnego stanu dostępnych narzędzi do tego zadania]


14
Python jest wielowątkowy, po prostu nie pozwala dwóm wątkom na jednoczesne uruchamianie kodu Pythona.
intgr

86
Nauczyłem się znacznie więcej z twojego pytania niż z odpowiedzi na nie.
Denis Otkidach,

2
@Denis: heh, dzięki chyba! W odpowiedziach pojawiło się kilka dobrych wskazówek, szczególnie intgr. Wiedziałem o wielu dostępnych opcjach i nie chciałem po prostu wypełniać odpowiedzi tymi
pytaniami,

5
> ludzie wydają się teraz preferować rozwiązanie oparte na wspólnej rutynie zamiast tradycyjnego reaktora / zorientowanego na oddzwanianie To nie jest rozsądne porównanie. „rozwiązania oparte na rutynach” i „zorientowane na reaktory” są ortogonalne. (Ignorując fakt, że Python nie ma coroutines) Spójrz na wbudowane funkcje zwrotne Twisted, aby zobaczyć, jak możesz mieć styl programowania, który wydaje się preferować, dzięki solidnej, dojrzałej warstwie sieciowej, która nie będzie narażać Cię na złożone osobliwości platformy.
Jean-Paul Calderone,

2
Kilka punktów do dodania: 1. Tornado działa bardzo dobrze w systemie Windows. Po prostu nie jest tak wydajny i skalowalny, ponieważ wykorzystuje selectdo multipleksowania I / O. Ale powinieneś być w stanie uzyskać z tego przyzwoitą wydajność dzięki tornado-pyuv . 2. Istnieje obecnie asyncio w Pythonie 3.3+ i jego backportu trollius który pozwala uruchomić dowolną aplikację Tornado w pętli zdarzeń (Twisted wspierane będą wkrótce).
schlamar

Odpowiedzi:


28

Podobał mi się moduł współbieżności Pythona, który wykorzystuje zarówno bezprogowe mikroprzerwy Pythona, albo Greenlety do lekkiego gwintowania. Wszystkie blokujące sieciowe we / wy są w sposób przejrzysty asynchroniczne za pośrednictwem pojedynczej libeventpętli, więc powinny być niemal tak samo wydajne jak prawdziwy serwer asynchroniczny.

Podejrzewam, że w ten sposób jest podobny do Eventletu.

Minusem jest to, że jego interfejs API jest zupełnie inny niż Python sockets/ threadingmoduły; musisz przepisać sporo aplikacji (lub napisać warstwę podkładki kompatybilności)

Edycja: Wygląda na to, że istnieje również cogen , który jest podobny, ale używa ulepszonych generatorów Python 2.5 dla swoich korpusów, zamiast Greenletów. To sprawia, że ​​jest bardziej przenośny niż współbieżność i inne alternatywy. Network I / O odbywa się bezpośrednio za pomocą epoll / kqueue / iocp.


@intgr: świetne linki. Dawno, dawno temu widziałem oba te rzeczy, które miałem nadzieję ujrzeć wypłukane. +1
jkp

3
Wygląda na to, że zbieżność jest martwym projektem, ponieważ była ostatnią aktualizacją cztery lata temu.
Gewthen

projekt jest martwy, podobnie Hyves!
Bahadir Cambel

1
Wiele się wydarzyło od Python 2.5. asyncio w Pythonie 3.5 jest świetne.
Joseph Sheedy

99

Twisted jest skomplikowane, masz rację. Twisted nie jest wzdęty.

Jeśli spojrzysz tutaj: http://twistedmatrix.com/trac/browser/trunk/twisted znajdziesz zorganizowany, wszechstronny i bardzo dobrze przetestowany pakiet wielu protokołów internetowych, a także kod pomocniczy do napisania i wdrażaj bardzo wyrafinowane aplikacje sieciowe. Nie pomyliłbym wzdęcia z kompleksowością.

Powszechnie wiadomo, że dokumentacja Twisted na pierwszy rzut oka nie jest najbardziej przyjazna dla użytkownika i uważam, że odwraca to uwagę niefortunnej liczby osób. Ale Twisted jest niesamowity (IMHO), jeśli poświęcisz czas. Zrobiłem i okazało się, że było warto, i poleciłbym innym, aby spróbowali tego samego.


4
@clemesha: być może masz rację i nie jest to przeładowane, ale wydaje się, że jest trochę za dużo, aby nakłonić mnie do zrobienia czegoś prostego. Rozumiem programowanie asynchroniczne, pracowałem w C ++ z boost :: asio, więc koncepcje nie są nowe, ale to wszystko gumph, które można porównać z robieniem pokręconych rzeczy: jest to zupełnie nowy świat, podobnie jak django jest dla rzeczy internetowych. Ponownie, gdy robię rzeczy sieciowe, pracuję z lekkim kodem WSGI i łączę tylko to, czego potrzebuję. Chyba konie na kursy.
jkp

7
@clemesha: erm, dzisiaj rzuciłem okiem: skręcony waży 20 MB! Nawet rdzeń ma 12 MB ... jeśli to nie jest rozdęte, nie jestem pewien, co jest.
jkp

29
Podstawowe Twisted API są dość małe (reaktor, odroczony, protokół). Większość kodu Twisted to implementacje protokołu asynchronicznego wykorzystujące te podstawy. „Wzdęcia” nie jest tu przydatnym przymiotnikiem (a nawet w większości przypadków). Rozmiar Twisted jest rozsądny ze względu na ilość rzeczy, które robi.
daf

56

gevent jest oczyszczony z eventletów .

Pod względem interfejsu API jest zgodny z tymi samymi konwencjami, co standardowa biblioteka (w szczególności moduły wątków i wieloprocesowe), jeśli ma to sens. Masz więc znane rzeczy, takie jak Kolejka i Zdarzenie, z którymi możesz pracować.

Obsługuje tylko libevent ( aktualizacja: libev od wersji 1.0 ) jako implementację reaktora, ale w pełni go wykorzystuje, oferując szybki serwer WSGI oparty na libevent-http i rozwiązujący zapytania DNS za pośrednictwem libevent-dns, w przeciwieństwie do korzystania z puli wątków, jak większość innych bibliotek robić. ( aktualizacja: ponieważ 1,0 cresy są używane do asynchronicznego zapytania DNS; pula wątków jest również opcją).

Podobnie jak eventlet, sprawia, że ​​wywołania zwrotne i odroczenia nie są konieczne przy użyciu greenletów .

Sprawdź przykłady: jednoczesne pobieranie wielu adresów URL , długi czat sieciowy z odpytywaniem .


4
Będę drugim geventem - po przejrzeniu wielu rozwiązań, gevent działał dla mnie bardzo dobrze. Pozwoliło mi to zachować większą część mojego istniejącego programu, a wymagane zmiany były trywialne - co najlepsze, jeśli kod musi być utrzymany za 3, 4, 5, ... lat, nadal sprawia, że sensu nikogo nie zna gevent, największy showstopper dla Twisted jest silny krzywa uczenia się, powoduje to problemy nie tylko w trakcie realizacji, ale również dalej w dół linii podczas konserwacji ...
Martin Tournoij

27

Naprawdę interesujące porównanie takich ram opracował Nicholas Piël na swoim blogu: warto je przeczytać!


2
Chociaż zgadzam się, że artykuł był interesującą lekturą, myślę, że warto rozważyć zasadność przedstawionych testów porównawczych. Zobacz komentarze tutaj: reddit.com/r/programming/comments/ahepg/…
clemesha

1
@clemesha, chociaż warto zwrócić uwagę na punkt na stronie reddit, test porównawczy został wykonany na dwurdzeniowej maszynie i prawdopodobnie nie cierpiał z powodu opisanej fatalnej wady. Przypuszczam, że możliwe jest, aby klient i serwer działały na tym samym rdzeniu, ale nie wydaje się prawdopodobne.
Peter Hansen

15

Żadne z tych rozwiązań nie pozwoli uniknąć faktu, że GIL zapobiega równoległości procesora - to po prostu lepsze sposoby uzyskania równoległości we / wy, które już masz z wątkami. Jeśli uważasz, że możesz zrobić lepiej we / wy, wykonaj wszystkie te czynności, ale jeśli masz wąskie gardło w przetwarzaniu wyników, nic tutaj nie pomoże, oprócz modułu wieloprocesowego.


Co jest złego w korzystaniu z wielu procesów?
Emil Iwanow

3
W ogóle nic, stąd propozycja użycia modułu wieloprocesowego.
Adam Hupp,

11

Nie posunąłbym się nawet do nazwania Twisted wzdęcia, ale trudno jest owinąć głowę. Dość długo unikałem uczenia się, ponieważ zawsze chciałem czegoś łatwiejszego do „małych zadań”.

Jednak teraz, gdy trochę z tym pracowałem, muszę powiedzieć, że posiadanie wszystkich dołączonych baterii jest BARDZO miłe.

Wszystkie inne biblioteki asynchroniczne, nad którymi pracowałem, są o wiele mniej dojrzałe, niż się nawet wydaje. Pętla zdarzeń Twisted jest solidna.

Nie jestem do końca pewien, jak rozwiązać stromą krzywą uczenia się Twisted. Może to pomóc, jeśli ktoś rozwidli go i wyczyści kilka rzeczy, takich jak usunięcie wszystkich cruft kompatybilności wstecznej i martwych projektów. Ale taka jest natura dojrzałego oprogramowania.


Jeśli kiedykolwiek sprawdziłeś, jak reaktor GTK jest implementowany w systemie Windows (ankietowanie co 10 ms: twistedmatrix.com/trac/browser/trunk/twisted/internet/... ), nie nazwałbyś tego „dojrzałym” ...
schlamar

2
Cześć @schlamar. Ten paskudny hack został zaimplementowany jako obejście niektórych dość poważnych błędów w GTK +, w czasach, gdy znacznie mniej obawiano się o wydajność energetyczną :). Ale piękno Twisted polega na tym, że możemy mieć ten błąd raz , naprawić go w ramach, a nasi użytkownicy nie muszą się tym martwić. Czy chcesz wprowadzić poprawkę, która rozwiązuje ten problem i usuwa się (przestarza, a następnie usuwa) PortableGtkReactor?
Glyph

1
@Glyph Dodałem pomocne porady na twistedmatrix.com/trac/ticket/4744#comment:2, jeśli ktoś inny chce rozwiązać ten problem, ponieważ niektóre z tych problemów nadal istnieją. BTW, mogłeś rozwiązać to znacznie wydajniej, planując połączenia zwrotne między dwiema pętlami zdarzeń.
schlamar

7

Kamaelia nie została jeszcze wspomniana. Jego model współbieżności opiera się na łączeniu ze sobą komponentów z przekazywaniem wiadomości między skrzynkami odbiorczymi i skrzynkami odbiorczymi. Oto krótki przegląd.


5
Użyłem Kamaelii do aplikacji - było to bardzo bolesne. IMHO istnieją inne, lepsze opcje współbieżności w pythonie (większość z nich jest wspomniana powyżej)
Ben Ford

7

Zacząłem używać skręconych do niektórych rzeczy. Piękno tego jest prawie dlatego, że jest „wzdęte”. Istnieją złącza dla niemal wszystkich głównych protokołów. Możesz mieć bot Jabbera, który będzie przyjmował polecenia i publikował je na serwerze IRC, wysyłał je do kogoś pocztą e-mail, uruchamiał polecenie, czytał z serwera NNTP i monitorował stronę internetową pod kątem zmian. Zła wiadomość jest taka, że ​​może to wszystko zrobić i może sprawić, że będzie to zbyt skomplikowane w przypadku prostych zadań, takich jak wyjaśnienie PO. Zaletą Pythona jest to, że dołączasz tylko to, czego potrzebujesz. Więc chociaż pobieranie może wynosić 20 MB, możesz dołączyć tylko 2 MB bibliotek (co wciąż jest dużo). Moja największa skarga na twisted polega na tym, że obejmują one przykłady, wszystko poza podstawowym serwerem tcp, na który jesteś sam.

Chociaż nie jest to rozwiązanie python, widziałem, że node.js zyskuje ostatnio znacznie większą przyczepność. Właściwie zastanawiałem się, czy nie przyjrzeć się mniejszym projektom, ale wzdrygam się, gdy słyszę javascript :)


Jestem wielkim fanem Pythona. - Sprawdź „Javascript - Dobre części” Douglasa Crockforda (3, 4 filmy). I zajrzyj na CoffeeScript. Okazuje się, że JS ma rzeczy, które powinien mieć Python, oprócz Składni, haha. CS próbował to złagodzić, ale jest trochę niezdarny w tym ...
Robert Siemer,

4

Jest dobra książka na ten temat: „Twisted Network Programming Essentials” Abe Fettiga. Przykłady pokazują, jak pisać bardzo Pythoniczny kod, a dla mnie osobiście nie wydaje mi się, że jest oparty na rozdętym frameworku. Spójrz na rozwiązania w książce, jeśli nie są czyste, to nie wiem, co oznacza czyste.

Moja jedyna zagadka jest taka sama, jak w przypadku innych frameworków, takich jak Ruby. Martwię się, czy to się powiększa? Nie chciałbym angażować klienta w środowisko, które będzie miało problemy ze skalowalnością.


4

Whizzer to mała struktura gniazd asynchronicznych, która wykorzystuje pyev. Jest bardzo szybki, głównie z powodu pyev. Stara się zapewnić podobny interfejs, z niewielkimi zmianami.


2

Spróbuj także Syncless . Jest oparty na coroutine (więc jest podobny do Concurrence, Eventlet i gevent). Implementuje nie-blokujące zamienniki dla socket.socket, socket.gethostbyname (itp.), Ssl.SSLSocket, time.sleep i select.select. To jest szybkie. Potrzebuje Stackless Python i libevent. Zawiera obowiązkowe rozszerzenie napisane w języku C (Pyrex / Cython).


2

Potwierdzam dobroć synchronizacji . Może korzystać z libev (nowszej, czystszej i lepszej wersji libevent). Czasami nie ma tak dużego wsparcia jak libevent, ale teraz proces rozwoju idzie dalej i jest bardzo przydatny.



0

Zapraszamy do zapoznania się z PyWorks, który ma zupełnie inne podejście. Pozwala instancjom obiektowym na działanie we własnym wątku i sprawia, że ​​wywołania funkcji dla tego obiektu są asynchroniczne.

Po prostu pozwól klasie dziedziczyć po zadaniu zamiast obiektu i jest asynchroniczna, wszystkie wywołania metod są proxy. Zwracane wartości (jeśli ich potrzebujesz) są przyszłymi serwerami proxy.

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 można znaleźć na stronie http://bitbucket.org/raindog/pyworks


1
Chociaż jest to interesujące i może być odpowiednie do niektórych zadań, używanie wątków do pracy w sieci działa źle (szczególnie w Pythonie z powodu GIL). I to było właśnie pytanie: zdarzenie oparte na frameworku lub z wieloma procesami. Więc twoja odpowiedź jest wyraźnie poza zakresem ...
schlamar
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.