Должен ли я использовать epoll или просто блокировать recv в темах? - PullRequest
4 голосов
/ 09 сентября 2011

Я пытаюсь написать масштабируемый пользовательский веб-сервер. Вот что у меня есть:

Основной цикл и интерпретатор запросов находятся на Cython. Основной цикл принимает соединения и назначает сокеты одному из процессов в пуле (это должны быть процессы, потоки не получат никакой выгоды от многоядерного оборудования из-за GIL).

Каждый процесс имеет пул потоков. Процесс назначает сокет потоку. Поток вызывает recv (блокирование) на сокете и ждет данных. Когда некоторые из них появляются, они передаются по конвейеру в запрос и затем отправляются через WSGI приложению, запущенному в этом потоке.

Теперь я слышал об epoll и немного растерялся. Есть ли какая-либо польза от использования epoll для получения данных сокета и последующей передачи их непосредственно процессам? Или я должен просто пойти по обычному пути, чтобы каждый поток ожидал на recv?

PS: Для чего на самом деле используется epoll? Похоже, что многопоточность и блокировка вызовов fd позволят сделать то же самое.

Ответы [ 2 ]

7 голосов
/ 09 сентября 2011

Если вы уже используете несколько потоков, epoll не дает вам дополнительных преимуществ.

Смысл epoll заключается в том, что один поток может одновременно прослушивать действия на множестве селекторов файлов (и реагировать на события для каждого по мере их возникновения) и, таким образом, обеспечивать многозадачность, управляемую событиями, не требуя порождениядополнительные темы.Потоки являются относительно дешевыми (по сравнению с порождающими процессами), но каждый требует , требует некоторых накладных расходов (в конце концов, каждый из них должен поддерживать стек вызовов).

Если вы хотите, вы можете переписать процессы вашего пула, чтобы они были однопоточными, используя epoll, что уменьшило бы общее количество используемых потоков, но, конечно, вам нужно было бы подумать, что вас это волнуетили нет - в общем, для небольшого числа одновременных запросов на каждого работника издержки порождения потоков не будут иметь значения, но если вы хотите, чтобы каждый работник мог обрабатывать 1000 открытых соединений, эти издержки могут стать значительными (ивот где epoll сияет).

Но ...

То, что вы описываете, звучит подозрительно, как будто вы в основном заново изобретаете колесо - ваше:

  1. основной цикл и интерпретатор запросов
  2. пул процессов

звучит почти так же, как:

  1. nginx (илиny Другой балансировщик нагрузки / обратный прокси-сервер)
  2. Предварительное разветвление tornado app

Tornado - это однопоточный модуль Python веб-сервера, использующий epoll и имеет встроенную возможность предварительного разветвления (это означает, что он порождает несколько своих копий как отдельные процессы, эффективно создавая пул процессов).Tornado основан на технологии, созданной для поддержки Friendfeed - им нужен был способ обрабатывать огромное количество открытых соединений для клиентов с длительным опросом, которые ищут новые обновления в режиме реального времени.

Если вы делаете это в качестве обученияпроцесс, то непременно изобретать заново!Это отличный способ учиться.Но если вы на самом деле пытаетесь создать приложение на основе подобных вещей, я настоятельно рекомендую рассмотреть возможность использования существующих, стабильных, совместно разработанных проектов - это сэкономит вам много времени, фальстартов иПотенциальные ошибки.


(PS Я одобряю ваш аватар. <3) ​​</em>

0 голосов
/ 09 сентября 2011

Функция epoll (и другие функции в том же семействе poll и select) позволяют вам писать однопоточный сетевой код, который управляет несколькими сетевыми подключениями. Поскольку нет многопоточности, нет необходимости в синхронизации, как это требовалось бы в многопоточной программе (это может быть трудно сделать правильно).

С другой стороны, вам необходимо иметь явный конечный автомат для каждого соединения. В многопоточной программе этот конечный автомат неявен.

Эти функции просто предлагают другой способ мультиплексирования нескольких соединений в процессе. Иногда проще не использовать потоки, иногда вы уже используете потоки, и поэтому проще просто использовать блокирующие сокеты (которые освобождают GIL в Python).

...