Что делает существенную разницу в производительности между eventlet и gevent?
Эти две библиотеки разделяют аналогичную философию и аналогичные проектные решения в результате. Но этот популярный тест WSGI говорит, что eventlet
работает медленнее, чем gevent
. Что отличает их производительность?
Как я знаю, ключевые различия между ними:
-
gevent
преднамеренно зависит от и libev
(libevent
, ранее), а eventlet
определяет независимый интерфейс реактора и реализует конкретные адаптеры с использованием select
, epoll
и витой реактор за этим. Имеет ли дополнительный интерфейс реактора критические характеристики?
-
gevent
в основном написан в Cython, а eventlet
написан на чистом Python. Изначально компилируется Cython так быстро, как чистый Python, для не очень-вычислительных, но IO-связанных программ?
-
Примитивы gevent
эмулируют интерфейсы стандартных библиотек, в то время как примитивы eventlet
s отличаются от стандартных и предоставляют дополнительный уровень для эмуляции. Повышает ли дополнительный уровень эмуляции eventlet
?
-
Является ли реализация eventlet.wsgi
хуже, чем gevent.pywsgi
?
Мне действительно интересно, потому что они в целом выглядят так похожими для меня.
Ответы
Ответ 1
Ну, gevent не "в основном" написан в Cython, хотя некоторые критические разделы.
Cython имеет огромное значение. Оптимизация процессоров работает намного лучше с скомпилированным кодом. Например, предсказание ветки разваливается в системах на базе VM, потому что косвенность ветвления на уровне выполнения VM непрозрачна для него. Отпечаток кеша более жесткий. Скомпилированный код здесь имеет огромное значение, и IO может быть очень чувствительным к задержке.
В аналогичном ключе libev очень быстро. Те же причины.
Кажется, что eventlet не должен был использовать концентратор select (Python 2.6 обычно по умолчанию использует epoll). Если бы он застрял в выборе, тем не менее, это сделало бы его очень медленным (потому что Python должен преобразовывать выбранный fd_set взад и вперед в список Python, поэтому он становится уродливым, когда он находится в середине цикла).
Я не делал профилирования, но я был бы готов поспорить, что libev/libevent plus Cython имеет большое значение. Примечательно, что некоторые из примитивов с резьбой находятся в Cython в gevent. Это большое дело, потому что много кода косвенно косвенно затрагивает их через IO и даже стандартную библиотеку в некоторых местах.
Что касается дополнительного слоя эмуляции eventlet, то, похоже, намного больше bounciness. В gevent путь кода, по-видимому, создает обратные вызовы и позволяет хабу вызвать их. Кажется, что eventlet выполняет большую часть бухгалтерии, которую хаб делает в gevent. Опять же, я не профилировал его. Что касается самки обезьян, они выглядят довольно схожими.
Сервер WSGI является еще одним сложным. Примечательно, что синтаксический анализ заголовков в gevent откладывается до стандартной библиотеки, тогда как они сами реализуют его в eventlet. Не уверен, что это большое влияние или нет, но неудивительно, что там что-то скрывается. Самое главное, что сервер eventlet основан на обеименной версии стандартной библиотеки BaseHTTPServer. Я не могу себе представить, что это очень оптимально. Gevent реализует сервер, который знает эмуляцию.
Ответ 2
Извините за поздний ответ.
В этом тесте есть две основные причины большой разницы в производительности:
- как указано выше, критические пути gevent сильно оптимизированы.
- этот тест проводит стресс-тестирование. Это больше не связано с IO, поскольку оно пытается заставить машину запускать как можно больше запросов. И это, где сияет цитонизированный код.
"В реальном мире", что происходит только во время "slashdot" всплесков трафика. Что важно, и нужно быть готовым, но когда это произойдет, вы реагируете, добавляя больше серверов или отключая тяжелые ресурсы ресурса. Я не видел теста, который на самом деле добавляет больше серверов при увеличении нагрузки.
Если, с другой стороны, контрольный образец будет имитировать нагрузку "обычного дня" (которая будет отличаться от одного веб-сайта к другому), но в целом может быть приближена к запросу, случайной паузе, повторению. Чем меньше эта пауза - тем больше мы имитируем трафик. Кроме того, клиентская сторона теста должна будет моделировать задержку. В Linux это можно сделать с помощью awesome netem [1], в противном случае, поставив небольшие задержки перед вызовами recv/send (что было бы очень сложно, потому что тесты обычно используют библиотеки более высокого уровня).
Теперь, если эти условия выполнены, мы фактически будем тестировать проблемы, связанные с IO. Но результаты не были бы слишком ужасными: все кандидаты успешно обслуживали 10, 50 и даже 200 кв. Скучно, правда? Таким образом, мы могли бы измерить распределение задержек, время для обслуживания 99% запросов и т.д. Gevent все равно показал бы лучшие результаты. Но разница вряд ли будет впечатляющей.
[1] Имитировать отложенные и отброшенные пакеты в Linux