Pytanie Co powoduje znaczącą różnicę w wydajności między wydarzeniem a gevent?


Te dwie biblioteki mają wspólną filozofię i podobne decyzje projektowe. Ale ten popularny test WSGI mówi eventlet jest znacznie wolniejsze niż gevent. Co sprawia, że ​​ich występ jest tak inny?

Jak znam kluczowe różnice między nimi to:

  • gevent celowo zależy od i jest sprzężony z libev (libevent, wcześniej) podczas eventlet definiuje niezależny interfejs reaktora i implementuje poszczególne adaptery wykorzystujące select, epolli zakręcony reaktor za nim. Czy dodatkowy interfejs reaktora generuje krytyczne wyniki?

  • gevent jest najczęściej napisany w Cython, podczas gdy eventlet jest napisany w czystym Pythonie. Czy natywnie kompilowany Cython jest szybszy od czystego Pythona, z powodu nie tak dużo programów obliczeniowych, ale związanych z IO?

  • Prymitywne gevent emulować standardowe interfejsy bibliotek podczas eventletPrymitywy różnią się od standardowych i zapewnia dodatkową warstwę do emulacji. Czy tworzy dodatkową warstwę emulacji eventlet wolniej?

  • Czy wdrożenie eventlet.wsgi tylko gorzej niż gevent.pywsgi?

Naprawdę się zastanawiam, ponieważ oni ogólnie wyglądają dla mnie tak podobnie.


16
2017-10-01 08:41


pochodzenie


Wątpię, byś otrzymał tutaj odpowiedź na tego rodzaju pytanie. Wypróbuj grupę ML / google. - gwik
Być może, ale oto użytkownik SO, który prawdopodobnie wie: stackoverflow.com/users/197910/denis-bilenko - kkurian


Odpowiedzi:


Cóż, gevent nie jest "w większości" napisany w języku Cython, chociaż niektóre krytyczne sekcje są.

Cython robi ogromną różnicę. Optymalizacje procesora działają znacznie lepiej dzięki skompilowanemu kodowi. Prognozowanie rozgałęzień, na przykład, rozpada się w systemach opartych na VM, ponieważ niedostrzeganie rozgałęzień na poziomie wykonania maszyny wirtualnej jest dla niej nieprzejrzyste. Ślad pamięci podręcznej jest mocniejszy. Skompilowany kod robi tutaj ogromną różnicę, a IO może być bardzo wrażliwy na opóźnienie.

W podobnym tonie, libev jest bardzo szybki. Te same powody.

Wygląda na to, że eventlet nie powinien był używać selektora select (zazwyczaj Python 2.6 jest domyślnie ustawiony na epoll). Jeśli jednak utknął na selekcji, to by to uczyniło naprawdę slow (ponieważ Python musi przekonwertować select fd_set w tę iz powrotem na listę Pythona, więc robi się brzydko, gdy jest w środku pętli).

Nie zrobiłem żadnego profilowania, ale chciałbym się założyć, że libev / libevent plus Cython robi dużą różnicę. Warto zauważyć, że niektóre z pierwotnych wątków są w Cython w gevent. To wielka sprawa, ponieważ wiele kodu dotyka ich pośrednio poprzez IO, a nawet standardową bibliotekę w niektórych miejscach.

Jeśli chodzi o dodatkową warstwę emulacji zdarzenia, wydaje się, że jest o wiele więcej bounciness. W gevent, ścieżka kodu wydaje się budować wywołania zwrotne i pozwolić hubowi je wywoływać. Wydaje się, że zdarzenie wykonało więcej operacji księgowych wykonywanych przez węzeł w gevent. Znowu jednak nie sprofilowałem tego. Jeśli chodzi o sam małpowanie, wyglądają dość podobnie.

Serwer WSGI jest kolejnym trudnym. Warto zauważyć, że analiza nagłówka w gevent jest odłożona do biblioteki standardowej, podczas gdy implementują ją same w zdarzeniu. Nie jestem pewien, czy to duży wpływ, czy nie, ale nie byłoby zaskoczeniem, gdyby coś tam się czaiło. Najbardziej wymowne jest to, że serwer zdarzeń jest oparty na niedopasowanej wersji standardowej biblioteki BaseHTTPServer. Nie mogę sobie wyobrazić, że jest to bardzo optymalne. Gevent implementuje serwer, który jest świadomy emulacji.


12
2017-10-04 01:25





Przepraszam za spóźnioną odpowiedź.

Istnieją dwa główne powody dużej różnicy w wydajności w tym benchmarku:

  • jak wspomniano wcześniej, krytyczne ścieżki gevent są mocno zoptymalizowane
  • ten benchmark przeprowadza testy warunków skrajnych. Nie jest już związany z IO, ponieważ stara się, aby maszyna uruchamiała jak najwięcej zgłoszeń. I tu właśnie świeci kod Cythonized.

"W prawdziwym świecie", który zdarza się tylko podczas "slashdot" wybuchów ruchu. Co jest ważne i trzeba być gotowym, ale kiedy to się dzieje, reagujesz, dodając więcej serwerów lub wyłączając funkcje obciążające zasoby. Nie widziałem benchmarku, który faktycznie dodaje więcej serwerów, gdy zwiększa się obciążenie.

Z drugiej strony, benchmark symulowałby ładunek "normalny dzień" (który byłby różny w zależności od witryny), ale generalnie mógłby być przybliżony do żądania, losowa pauza, powtórzenie. Im mniej ta przerwa, tym większy ruch symulujemy. Również strona benchmarku po stronie klienta musiałaby symulować opóźnienie. W Linuksie można to zrobić za pomocą niesamowitego netema [1], w przeciwnym razie, wprowadzając małe opóźnienia przed recv / send calls (co byłoby bardzo trudne, ponieważ testy porównawcze zwykle korzystają z bibliotek wyższych poziomów).

Jeśli te warunki zostaną spełnione, będziemy faktycznie porównywać problemy związane z IO. Ale wyniki nie byłyby zbyt niesamowite: wszyscy kandydaci z powodzeniem obsłużyli 10, 50, a nawet 200 qps ładunków. Nudne, prawda? Moglibyśmy zatem zmierzyć rozkład opóźnień, czas na obsługę żądań 99%, itp. Gevent nadal wykazywałby lepsze wyniki. Ale różnica nie byłaby imponująca.

[1] Symuluj opóźnione i upuszczone pakiety w systemie Linux


1
2018-01-24 10:05



Celem każdego benchmarku jest pokazanie limitów. Umieszczenie obciążenia "normalnym dniem" (cokolwiek to znaczy) na obiekcie może pokazać tylko, czy jest ono zdolne do wykonania pod tym obciążeniem. Jeśli to wszystko, czego potrzebujesz, to jest w porządku, ale to nie jest punkt odniesienia. - Alex K
@AlexK Myślę, że przegapiliście tę część: "Abyśmy mogli zmierzyć rozkład opóźnień, czas na obsługę 99% zapytań itd." Nawiasem mówiąc, czas na obsłużenie żądań N% jest o wiele bardziej przydatny niż maksymalny rps. - temoto
Nie tęskniłem za tym. Nie ma znaczenia, co próbujesz zmierzyć. Dopóki nie spychasz go do granic wytrzymałości, nie porównujesz go. To był mój punkt widzenia. - Alex K