Как стать автором
Обновить

Комментарии 36

Не понял, зачем торнадо работать с asyncio? Синтаксис же почти один в один, что это даст торнадо? К тому же gen, в отличии от asyncio, имеет один синтаксис во 2 и 3 версии питона. Если речь о совместном использовании библиотек, это давно возможно: www.tornadoweb.org/en/stable/asyncio.html
Вот вы сами и ответили на вопрос «зачем» — чтобы использовать библиотеки, сделанные для других систем. Причем если я создаю что-то для asyncio это можно будет использовать и в tornado. А наоборот не получится. Какую библиотеку делать перспективней?

P.S. Вообще-то торнадо научилась понимать asyncio event loop не так уж и давно — три месяца назад :)
Понял, спасибо :) А вы orm прикрутить к aiopg не планируете, случаем?
ORM — нет, не планирую. По крайней мере сейчас мне это не нужно
Во-первых, спасибо за библиотеки. Прекрасно, что уже появляются практические примеры применения asyncio.

Во-вторых, у меня есть к вам огромная просьба — напишите статью про то, как применять asyncio на практике. Я прошелся по документации, почитал введение в Twisted (чтобы видеть перспективу) нашел пару примеров в доках и пару в сети — и все. Этого очень мало, чтобы вникнуть в тему как следует. Asyncio дает возможность писать асинхронные приложения как колбеками, так и корутинами, и было бы круто узнать особенности этих подходов на примерах.

Я уверен, что туториал от кор-девелопера — это то, что оценит много людей, не только на Хабре, но и вообще в коммьюнити Питона. Если что, с удовольствием займусь переводом на английский.

Спасибо!

P.S. AMA на Реддите в r/python не хотите замутить? :-)
1. Пожалуйста.
2. Я начинал писать серию таких статей но застрял на полпути. Сделать что-то толковое требует немалого времени и драйва. Иначе ничего не выходит. Если статьи и появятся то точно не на хабре а у меня в блоге. Хабр ревнив и требует эксклюзивности, а это не нравится уже мне.
На callbacks писать не надо, это сложно и вообще может быть нужно только разработчикам библиотек. Если либы хорошие то пользователю кроме yield from ничего требоваться не должно.
P.S. Что такое AMA на Реддите в r/python не знаю, так что, наверное, замутить не хочу.
Выкиньте доки по twisted в окно, imho с торнадо проще и быстрее разобраться. А принципы примерно одинаковые. Про asyncio пока не скажу, но принципиально все тоже самое.

Что собственно вы хотите делать с корутинами? Фактически это теже колбэки, только выглядящие как синхронный код.

def process(self, html):
print «got html:», html

def foo(self):
async_fetch(«example.com», callback=self.process)

вместо этого пишем

@ gen.coroutine
def foo(self):
html = yield async_fetch(«example.com»)
print «got html:», html

где async_fetch, загружает страницу и вызывет self.process которому передает загруженны html код.
Это все грубо говоря и размахивая руками, есть еще много тонкостей: foo теперь future которую тоже нужно ждать (yield), async_fetch должен быть генератором, exceptions надо ловить итд.
Да, и важно понимать что такое генераторы и как они работают. На stack overflow был знаменитый пост где все объяснено.
Если советуете выкинуть twisted, то почему не распространаете совет и на tornado?
asyncio принципиально похож на twisted/tornado ровно в том смысле, в каком программа на ассемблере похожа на программу на C: они ведь обе компилируются в машинный код!

С корутинами я хочу (и уже имею) несколько критически важных вещей:
1. Линейная структура кода. Все известные мне программисты мыслят линейно. Их можно научить думать в терминах обратных вызовов (я в свое время писал и для twisted и для tornado если что) — но это не совсем легко. В результате программа читается плохо и как минимум обработка ошибок очень страдает. Непойманные исключения улетают в никуда, это повсеместная проблема (кто-то где-то да забудет). Если исключение таки поймано, то у него ужасный traceback. В twisted предпринимали серьезные усилия чтобы этот traceback выглядел читаемо. С частичным успехом.
2. Удобная отладка. Если остановился на строчке с yield from, то 'next' переходит на следующую строку а не начинает отлаживать внутренности event loop.
3. Продуманный набор функций/классов для запуска, ожидания, отмены корутин, таймауты, блокировки, очереди и пр. В tornado.gen есть только очень куцый минимум того, что работает в asyncio

P.S.
twisted был великой библиотекой. Десять лет назад.
tornado, пожалуй, получше twisted. Но сравнение с asyncio с треском проигрывает. Единственное преимущество на сегодня — tornado.web, но за полгода и для asyncio появится достойная альтернатива (собственно говоря они уже есть но каждая в чем-то недоделана).
Я советую выкинуть доки от twisted, а не сам twisted. Для начинающих там все очень долго и путано. Разобраться и начать работать с tornado гораздо быстрее. Впрочем это мой опыт и я на нем не настаиваю.

Asyncio выглядит интересно и я думаю попробовать переписать что-нибудь под него, чтобы составить собственное мнение. Но вобщем с asyncio есть три большие проблемы:
  • Python 3.4. Все сидят на 2.6-2.7 и переходить на 3.x не собираются. Печально, но факт. Twisted/Tornado работают в 2.6-2.7
  • Переводить продакшн код с Twisted/Tornado на Asyncio тоже особо незачем.
  • Для asyncio пока мало библиотек. Надеюсь скоро это изменится.

Так что asyncio пока только для новых проектов и смелых/отчаянных команд. Хотя есть надежда что asyncio поможет сдвинуть переход на 3.x с мертвой точки.

Как по мне, так asyncio, twisted и tornado, одно и тоже с разницей в API и деталях, когда как треды и greenlets уже совсем другой принцип.
Ok, так согласен
Twisted/Tornado работают в 2.6-2.7

Prerequisites: Tornado runs on Python 2.6, 2.7, 3.2, 3.3, and 3.4.
я думаю попробовать переписать что-нибудь под него, чтобы составить собственное мнение.

Рекомендую — что-нибудь не очень ценное :) На форумах пишут, и я согласен: «портируясь на async, никогда не знаешь, какой кусок старого кода тебя утопит, отъев более 100мс внутри ioloop». У нас так вёл себя, например, DNS при отпавшей сети.
В asyncio запросы DNS делаются в thread pool если что.
И вообще если не думать — выстрелить себе в ногу можно абсолютно любым инструментом.
asyncio в этом отношении не проще и не сложнее.
А что с производительностью? Для двух соединений получающих данные мелкими порциями (100-200 байт) каждые 1-5ms, что будет выгоднее: два потока с zmq.Poller или один поток с вашим ивент лупом?
про потоки не понял. Имеются в виду threading.Thread или что-то другое?
Да, threading.Thread.

Можно даже рассмотреть 3 варианта:
  1. Два threading.Thread с zmq.Poller
  2. Один threading.Thread и один aiozmq ивент луп
  3. Два threading.Thread в каждом по aiozmq ивент лупу.
Я пробовал 2 потока zmq vs aiozmq, получилось где-то 5600 и 6200rps соответственно (5-7б на сообщение).
Можно взглянуть на код?
Примерно такой. Этот у меня выдал 5500 (zmq) и 7100 (aizmq) на py 3.4.
В примере с потоками я вижу только один поток клиента.

Мне хотелось сравнить aiozmq именно с многопоточным вариантом, чтобы понять, как эффективно и честно выделяется время потокам на работу с сетью

Кроме того у вас используется два zmq контекста в одном процессе. Если заменить на zmq.Context().instance(), производительность изменится?
Спасибо. Дальнейшие комментарии по тебе буду оставлять в вашем блоге.
Почему только request-reply? Остальные паттерны не ложатся на архитектуру asyncio?
ложатся прекрасно. Просто request-reply должен быть самый сложный и медленный для aiorpc.
Майк Бейер довольно жёстко и, вроде бы, обоснованно, с бенчмарками прошёлся по асинхронному в/в в подключении к БД: techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases
Вкратце: «Оно не надо; это только для веба».
Что вы думаете о его статье?
У Майка своя колокольня — SQLAlchemy никогда не заработает с корутинами.
Но в целом согласен: «оно не надо, это только для веба».
Вопрос: вы, случайно, не разработкой для веба на хлеб зарабатываете?
Тогда ненужность асинхры — не звучит.
Частично для веба. Но веб-то бывает разный: если не случается с10к, то можно по-всякому подойти. А даже если и случится. Кто-то пробовал разрешить на сервере 400 воркер-тредов?

В обсуждениях на Реддите, на Y-Combinator и в блогах люди высказывались по-разному, но с цифр в пользу async io почему-то никто не привёл :)

На YC дядя, не называя конкретики, пишет: «Я работал в одной из самых больших в мире соцсетей. Там на каждый сокет порождается тред, а потом ещё и подтреды. И нормально. В принципе, ограничение на количество сокетов у нас есть… примерно 4 миллиона на один сервер».
Может у дядьки с одной из самых больших в мире соцсетей одни из самых мощных в мире серверов, откуда я знаю?

Попробуйте 400 worker-threads и классический сервер о 16 ядрах начнет спотыкаться. На 1600 — ляжет и заплачет. В то время как asyncio (tornado, twisted, nodejs) будет работать и не жужжать.

Но основной затык не в этом.
Так вышло, что синхронные сервера для питона все работают по стандарту WSGI. Который не поддерживает websockets и прочие варианты push-messages просто по определению. И это проблемма.
Возможно, я лично проверю бенчмарки, благо, Бейер их выложил. У него ноут о 4 или 8 ядрах справлялся с синхронными запросами лучше, чем asyncio; один из тестов был на 350 воркеров.

Правда, в его тесте участвует только голый код на Python + драйвера, безо всяких серверов и фреймворков. Что сервера и фреймворки добавляют катастрофический оверхед, я ни минуты не сомневаюсь. В этом смысле Tornado, с которой у меня небольшой опыт есть, выигрывает: в нём оверхеда, равно как и функционала, не слишком много.

А если нужно держать открытыми тысячи сокетов — тут, конечно, пора экономить; но на эту область Бейер и не замахивался.
Один из пойнтов Бейера и был, что IO-bound задачи на Пайтоне очень быстро превращаются в CPU-bound. Конечно, если спящих сокетов не на порядки большое, чем живых.
Автора SQLAlchemy я не могу заподозрить в питононенавистничестве :)
Его можно заподозрить в защите SQLAlchemy.
Потому что для асихронных библиотек она катастрофически не подходит.
Asyncio/Tornado расходуют много* cpu на промолачивание самой асинхрощины (перекладывание функций туда сюда, жонглирование со списками, регистрация, удаление и перебор событий и т.п.) поэтому оно работает гораздо медленнее чем синхронный подход, так пустое wsgi приложение может работать в 2 раза быстрее пустого async питон приложения.
Асинхрон выгоден (иногда необходим) на долго висящих соединениях (веб-сокеты, http-закачка...), где не выгодно держать гору потоков.

На обычных, коротких web запросах async не (всегда) оправдан, например такой сценарий — зачастую достаточно 50-100* потоков wsgi (~3-6Mb RAM) что-б нагрузить БД (для одного сервера*), а больше потоков смысла вводить нет, т.к. уже уперлись в БД.
В данной ситуации async может показать результаты хуже, особенно если запросы отрабатывают быстро, питон начнет упираться в CPU, придется форкать приложение, и в итоге БД будет иметь меньше CPU, а значит меньшая общая производительность.
Конечно все зависит от деталей.

Ещё разработчики торнадо предлагали использовать блокирующий доступ к БД в самом торнадо (они так делали у себя в friendfeed).

И это все без учета сложности async кода о котором можно филосовствовать часами.
Еще раз. Мне на сайте нужна система извещений пользователя о том что ему пришло какое-то сообщение.
WSGI не предполагает ничего подобного.
Если делать pull requests (не websockets и даже не long polling, это всё выходит за рамки WSGI) с приемлемой частотой (раз в секунду хотя бы) — быстро завалим любой сервер, как бы быстро запросы не отрабатывали.
Я про ваш проект ничего не говорил, async для веб-сокетов самое-то.
Речь про то, что из-за популярности (пропаганды) async, многие начинают делать «блоги» (обычные сайты) на асинхронных фреймворках.
В том-то и дело.
1. Пишем блог
2. Добавляем комментарии (в топку disqus, мы же велосипедим!)
3. Добавляем runtime notifications для комментариев
На пункте 3 приплыли.

На самом деле не так много сайтов обходятся без такой системы.
Ничего не приплыли, делается микросервис (в сотню строк) который через zmq получает евенты и отправляет через вебсокеты, и не надо весь проект делать асинхронным.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории