#python #python-asyncio #socketserver
#python #python-asyncio #socketserver
Вопрос:
Я собираюсь создать веб-сервер, который мог бы получать много подключений. Эти 10000 подключенных пользователей отправят на сервер номера, и сервер вернет эти квадратные числа пользователям обратно. 10000 подключений — это слишком много, и здесь уместен асинхронный подход. Я нашел две библиотеки для Python 3.4, которые могут помочь:
socketserver и asyncio
С библиотекой socketserver мы можем использовать классы ThreadingMixIn и ForkingMixIn в качестве асинхронных обработчиков. Но это ограничено количеством ядер. С другой стороны, у нас есть библиотека asyncio. И я не понимаю, как именно это работает. Какую из них мне следует использовать? И могут ли эти две библиотеки работать вместе?
Ответ №1:
Существуют разные подходы к асинхронному программированию.
Первый подход заключается в мониторинге операций ввода-вывода с использованием потоков и управлении этими операциями неблокирующим образом. Это то, что SocketServer
делает.
Второй подход заключается в мониторинге операций ввода-вывода в главном потоке с использованием цикла событий и селектора. Обычно это то, что люди имеют в виду, когда говорят об асинхронном программировании, и именно это asyncio
, twisted
и gevent
делают.
Однопоточный подход имеет два преимущества:
- это ограничивает риск состояния гонки, поскольку обратные вызовы выполняются в том же потоке
- это избавляет от накладных расходов на создание одного потока для каждого клиента (см. Проблему 10K)
Вот пример сервера asyncio TCP. В вашем случае просто замените handle_echo
сопрограмму своей собственной реализацией:
async def handle_client(reader, writer):
data = await reader.readline()
result = int(data.decode().strip()) ** 2
writer.write(str(result)).encode())
writer.close()
Она должна легко справляться с тысячами клиентов.
Комментарии:
1. Вы упомянули модуль selectors . В чем преимущество использования селекторов непосредственно для сервера сокетов, как в примере, который они показывают по ссылке?
2. @Jay Упомянутый вами пример интересен в том смысле, что он показывает, как можно написать TCP-сервер, который обслуживает несколько клиентов одновременно в одном потоке, используя селектор и некоторые обратные вызовы. На практике гораздо проще использовать asyncio, как показано в этом другом примере TCP-сервера .
3. Итак, asyncio реализует что-то подобное под капотом? Означает ли это, что selectors работает быстрее, поскольку он находится на более низком уровне абстракции?
4. @Jay Да, это так . Но подход с использованием простого селектора не обязательно быстрее для таких программ, поскольку большая часть времени обычно тратится на ожидание ввода-вывода. Кроме того, вы все еще можете подключить uvloop к asyncio для повышения производительности.