Pull to refresh

Comments 24

Вспомнил, как столкнулся с deferred в twisted и довольно долго вникал, как это работает. Потом привык и оказалась очень удобная штука.
Поднять бы хабракат ко второму абзацу ,.)
Я долго думал, где его поставить, остановился на текущем варианте, вроде бы и много получилось, но с другой стороны до хабраката осталась вся вводная часть.
Пример асинхронного программирования:
Есть соцсеть типа хабра, где разделено все на 3 части — информеры слева, статьи и комменты. Каждая часть на своем сервере.
Открытие идет на аяксе, подгружая все три части и формируя страницу. При этом пока идет загрузка камментов, на информере может пройти обновление и там выйдет запись — опаньки, не открывайте камменты для статьи такой-то, бо тормоза и трафик!
черт возьми, красиво реализовано
UFO just landed and posted this here
Честно — не до конца понял концепт, но само асинхронное программирование люблю и уважаю.

В свое время активно использовали, только код перевели из «обычного» в вариант «конечные автоматы»+«слоты и сигналы»

В финале ускорились почти в 200(!) раз что позволило перевести систему с пней4 на ARM\400Мгц и по индукции кластеризовать работу…
потому как(если подумать) если вы что-то ждете асинхронно — по сути по барабану где это будет работать и как команда на исполнение блока до этого где добереться
Асинхронное программирование — очень хорошая штука в своей области. А на тему «как» и «где» доберется — Deferred как раз позволяет это сделать гораздо прозрачнее, однотипнее и понятнее. Постараюсь в следующих постах раскрыть тему.
Честно скажу — вы мой самый любимый писатель
Что не пишете — пишите правильно и почему-то… именно что о чем полезно было бы почитать именно сейчас для текущих заданий

Но… питон не для нас :(
Без поллитры не разобратся (:
В закладки!
Интересно, насколько это эффективно. Я как плюсер, предпочитаю ивенты или другие механизмы, поллингу и подобным вещам, поскольку последние отжирают процессорное время (еще бы — крутится в цикле и выполнять poll()). С одной стороны программа не будет блокироватся, с другой — это тоже принесет дополнительную нагрузку, потому как ассинхронное IO необходится без дополнительных потоков (запускается поток, который занимается поллингом и потом вызывает коллбек), а в Питоне есть GIL…
Асинхронный ввод-вывод очень эффективен как подход, причем дополнительных потоков нет. Пример таких программ был в статье, приведу пару высокопроизводительных еще раз: nginx, HAProxy.

Что касается непосредственно Deferred, их реализация достаточно компактная, ничего сложного, больших накладных расходов они не приносят.

Как факт: наш сервер вещаний (RTMP) на одном ядре процессора обрабатывает 70-150 Мбит/с (порядка 1000 одновременных соединений), в пике до 250 Мбит/с. Он написан на Python/Twisted.
Я знаю, что такое ассинхронное IO и эффективность его применения. Штука в том, что при синхронном IO прием данных происходит в контексте вашего трида. При ассинхронном IO в очередь APC потока добавляется новый APC. Прием данных происходит в контексте _другого_ потока и IO реквест помечается как завершенный. Затем, когда трид входит в alertable state (ждет где-то), запускается ваш APC коллбек.

Хотя по сути вы правы, запуск APC происходит в вашем же триде, так что проблем быть не должно.
Касательно производительности… 250 Мбит — не так уж много, одно ядро Core 2 Duo по идее может отдавать 1 гигабит при загрузке в 80-85%. Хотя конечно, все зависит от того, что вы еще обрабатываете в данный момент :)

Вопрос не в тему. nginx однопоточный. Подобное приложение на twisted фактически тоже (не считая операция в сетевом стеке). На многоядерных машинах, как вы перераспределяете коннекшены, дабы равномерно загрузить все ядра?
Я не знаю, что такое 'APC' в данном контексте, но потоков на уровне приложения в Twisted для ввода-вывода нет.

На многих ядрах запускается много процессов, потому что всё равно одним сервером это не ограничивается (приложение масштабируется по мере роста нагрузки). 250 Мбит/с — это уже конечный RTMP трафик, не самый удобный для этого дела протокол на самом деле )
Внесите ясность пожалуйста:
Правильно я понимаю, что любой код в любом случае «завершается» `reactor.run`ом и что по сути реактор и есть сердце Twisted без которого `Deffered` не работают. Или я не прав?
Реактор — сердце событийной системы, он вызывает select/poll/epoll/kqueue, которые обеспечивают возможность сетевого ввода-вывода. Как таковые Deferred на него не завязаны, но без реальных асинхронных событий (ввод-вывод) они большого смысла не имеют, поэтому на практике во всех Twisted-приложениях реактор работает от начала и до конца. Реакторы умеют интегрироваться со всякими GUIшными event loop'ами, поэтому большой проблемы в этом нет.
Для Си++ есть OpenSource фреймворк ACE, в котором реализован паттерн Active Object, который, по моему (я из него только объект Future использовал), делает то же самое.
ИМХО, это что-то похожее, но… простите меня… Deferred — это красиво и элегантно, а там какой-то тихий ужас ;)
Тут описана релизация, которая действительно «тихий ужас», но, к счастью, она скрыта от пользователя фреймворка. А по использованию так же проста.
Почитайте исходники Deferred, там всего полторы страницы кода ;) Может, будет интересно. На C++ его реализация далеко не так тривиальна, но это специфика языка, а на Python/JavaScript это точно занимает полторы страницы. Как и интерфейс Deferred.
в общем-то однозначно скачать что block+threads медленее нельзя. Если например сделать 10 потоков в си, которые будут что-нибудь качать, то по скорости будет аналогично асинхронному варианту. А вот если нужно 10тыс потоков создавать каждую секунду — то да, здесь асинхронный вариант шустрее.

В асинхронном подходе намного проще ловить ошибки. Так, например в питоне нельзя насильно разорвать заблокированный сокет, пока в последнем не сработает таймаут. В случае асинхронного варианта — фактически достаточно убрать у него обработчик.
block+threads сложнее программировать в общем случае из-за необходимости явной синхронизации
Это не совсем так. В случае сверх-лёгких нитей а-ля в Limbo (OS Inferno) или Go — базирующихся на CSP, с IPC через каналы — код получается намного яснее и проще event/callback-ориентированного да и никаких проблем с созданием тысяч нитей каждую секунду тоже нет.
Мой комментарий относился ни к скорости создания нитей, ни к красоте кода.

В общем случае, чистый код в нитях (без другой модели программирования, например Actor в Erlang) крайне труден в поддержке/разработке из-за наличия тех или иных синхронизаций, число которых для получения приемлемой скорости растет.
Sign up to leave a comment.

Articles