вторник, 17 мая 2016 г.

asio_samples 1.0.0 released

Первый релиз состоялся: asio_samples-1.0.0.

2 года прошло с тех пор, как проект переехал на GitGub. За это время я успел сменить место работы и полностью переехать на Git как дома, так и в офисе. Успел попробовать CMake и полностью перевел сборку "asio samples" на CMake, убрав из репозитория все другие проекты. Успел получить бесплатную Open Source лицензию для CLion. Ради CLion пришлось начать использовать MinGW и теперь основное время я провожу в CLion с MinGW, но иногда проверяю детали в MSVS 2015 Community Edition. С удовольствием ("джва года ждал") могу подтвердить, что CLion является IntelliJ IDEA для C++ (ну разве что медленнее - тут C++ виноват).

В последнее время в "asio samples" начали появляться unit-тесты (на Google Test - популярно / удобно и есть интеграция с CMake / CLion). В планах увеличить покрытие основных сценариев использования и наиболее критичных (самых неприятных и неочевидных) пограничных случаев.

пятница, 14 февраля 2014 г.

Asio samples were moved to GitHub

Для читателей блога и нелюбителей SourceForge (есть за что) перепечатываю эту запоздалую "новость":

Asio samples were moved to GitHub.
The SourceForge SVN repository and files won't get updates anymore.
There won't be any other announces in asio-samples mailing list, however I'll continue to answer questions posted there.
The preferred way for bug reporting is GitHub issues page.

суббота, 7 сентября 2013 г.

await добрался до C++

Смотрю GoingNative 2013.

Особенно интересно выступление по теме "Bringing await to C++". "Асинронность" (ожидаемо) идет в массы и становится трендом. Настолько, что ее поддержку внедряют в компилятор и в будущий стандарт C++ (надеюсь, что последнее все-таки свершится). Понятное дело, это все для того, чтобы сделать программирование "асинхронности" максимально удобным для обывателей "среднестатистического программиста" и лучше оптимизировать.

Stackfull coroutines (наконец-то) идут в массы. Всего какой-то год назад "текли слюни" при взгляде на поддержку await в C#! Видимо, компании, которые массово используют C++ и потому влияют на его развитие, действительно активно используют асинхронные алгоритмы и остро нуждаются в средствах, способных облегчить их реализацию на C++ (а заодно и лучше оптимизировать подобный код).

Кто еще сомневается в необходимости работать с вводом-выводом асинхронно даже в клиентской части (например, уеt another messenger)? На "рельсы асинхронности" уже планируют перевести не только сетевой ввод-вывод - смотрите, примеры-то у всех (кто говорит, про PPL, std::future::then и даже про уже существующий WinRT) работают со "старыми добрыми" файлами (а, может быть, просто у них пока нет чего-то более-менее стандартного и краткого для сетевого ввода вывода?). И не только (правда, там уже делают больший упор на lazy-вычисления).

P.S. Q&A Panel особенно порадовала. Определенно, нынешний GoingNative гораздо лучше предыдущего и лучше уже прошедшего C++Now. Отличные докладчики (хотя их состав почти не меняется) с неплохим чувством юмора!

воскресенье, 1 сентября 2013 г.

::boost::asio::io_service::strand и лишние проверки

Среди заголовочных файлов "asio samples" лежит "скромный" ma/strand_wrapped_handler.hpp. Когда-то, разбираясь с invocation strategy и io_service::strand, я наткнулся на то, что стандартно обернутый через asio::io_service::strand::wrap() функциональный объект делает проверку (на исполнение в контексте strand-а) и в asio_handler_invoke, и в своем operator(). Так вот, обычно достаточно делать такую проверку только в asio_handler_invoke. "Обычно" в этом предложении означает: для всех классов Boost.Asio и вообще везде, где вы сами не вызываете напрямую operator() у функционального объекта, "обернутого" через strand. В противном случае, при использовании asio_handler_invoke с таким образом обернутым функциональным объектом (вспоминаем, что Boost.Asio всегда вызывает все user-defined обработчики только так), проверка на исполнение в контексте strand будет выполняться дважды! Данная операция не такая уж и легкая (использует мютексы/критические секции). Кому интересно, загляните в исходники Asio.

С тех пор (давно) вместо asio::io_service::strand::wrap() везде в "asio samples" я использую свой макрос MA_STRAND_WRAP(strand, handler), определенный в том самом ma/strand_wrapped_handler.hpp. Моя strand-"обертка" для функционального объекта использует asio::io_service::strand::dispatch только в asio_handler_invoke.

Автору Asio я писал (давно, в список рассылки). Он ответил, что те, кого волнуют подобные двойные проверки (я согласен с тем, что еще не известно, как/насколько они скажутся на производительности) смогут аналогично мне сами написать свою обертку. Кхм... В свете того, что Asio все чаще используется даже высоконагруженными гигантами вроде Mail.ru (и, кажется, уже давно в Yandex), хотел бы порекомендовать пользователям Asio по-чаще смотреть в исходники самой библиотеки Asio.

среда, 31 июля 2013 г.

Ожидаемая C++ IDE от создателей замечательной IntelliJ IDEA

Давно ждал новостей о C++ IDE от гениальных JetBrains. Сожалел, что не смог попасть на день открытых дверей JetBrains. А недавно наткнулся в RSS Хабра на "Видео с дня открытых дверей JetBrains", где есть видео презентации "C++ IDE и как с ней бороться":



Чтож, c нетерпением жду ReSharper с поддержкой C++ и саму С++ IDE. Жизнь в мире C++ становится все более комфортной и все менее олдскульной (Far Manager + Colorer Plugin!?).

Asio samples 0.6.0 is out

Вышла очередная бета asio samples 0.6.0. Приведу здесь только основные изменения:
  • Класс ma::console_controller переименован в ma::console_close_guard и реализован через boost::asio::signal_set для *nix и через ma::windows::console_signal (см. ниже) для Windows.
  • Представлен класс (расширение Boost.Asio) ma::windows::console_signal (+ ma::windows::console_signal_service). Данный класс может использоваться как каркас для расширений Boost.Asio, использующих внутренние потоки. Он будет подробнее освещен в отдельной статье позже. Пока же скажу лишь, что класс ma::windows::console_signal (определен только при сборке для Windows 2000 и выше) позволяет асинхронно ожидать сигнала к закрытию консольного приложения пользователем (путем использования комбинации клавиш Ctrl+C/Ctrl+Break, закрытия окна или выхода из системы/завершения работы компьютера)
  • Выделены отдельно и изменены классы ma::detail::intrusive_list и ma::detail::intrusive_slist: добавлены ссылки на конец списка, которые позволили реализовать конкатенацию списков со сложностью O(1).
  • Добавлена поддержка Qt 5, Boost C++ Libraries 1.53/1.54.

Остальные детали беты 0.6.0 можно прочитать в списке рассылки.

Updated
Исправление ошибок в классах ma::console_close_guard и ma::windows::console_signal_service вылилось в asio samples 0.6.1.

понедельник, 29 октября 2012 г.

Asio samples 0.5.0 is out

Вышла очередная бета asio samples 0.5.0. Приведу здесь основные изменения, которых хватило аж на смену среднего номера версии.

Во-первых, сильно изменился (в лучшую сторону) класс ma::handler_storage. Теперь он поддерживает функциональные объекты с operator()(void) при специализации ma::handler_storage<void>.

Кроме того, наконец-то, метод ma::handler_storage::target() стал типизированным, что избавляет его пользователей (см. проект nmea_client) от неприятных reinterpret_cast. По умолчанию ma::handler_storage::target() возвращает void*, но теперь, при желании, этот тип можно специфицировать указав его в качестве второго шаблонного аргумента ma::handler_storage.

При такой специализации для класса ma::handler_storage_service должно быть доступно преобразование static_cast<Target*>(Handler*), где
  • Target - специфицированный для ma::handler_storage::target() тип (т.е. Target* ma::handler_storage<Arg, Target>::target()).
  • Handler - тип функционального объекта, хранимого в ma::handler_storage.

Второе крупное нововведение заключается в поддержке проектами qt_echo_server, echo_server, async_connect и asio_performance_test_client режима io_service-per-work-thread (по аналогии с HTTP Server 2 из примеров Asio). Для CLI за этот режим отвечает параметр demux_per_work_thread. Для Windows режим io_service-per-work-thread по умолчанию отлючен (--demux_per_work_thread=0, false, off). Для других платформ - по умолчанию включен (--demux_per_work_thread=1, true, on).

Остальные детали беты 0.5.0 можно прочитать в списке рассылки.

Updated
Исправление ошибок и расширение поддержки лямбд вылилось в asio samples 0.5.1.

четверг, 19 июля 2012 г.

asio performance test

Данное сообщение будет служить для сбора всей информации, что мне удастся собрать по теме производительности Asio. Буду рад видеть в комментариях вопросы/критику/дополнения и результаты/методики тестов читателей.

Для начала выложу самое простое – отчеты профилировщика MS VS 2010. И клиент и сервер работали одновременно на моей домашней машине (причем без отключения прочих приложений вроде uTorrent и MS Outlook):
  • MS Windows 7 Pro x64 SP1 + все обновления на 19.07.2012
  • ASUS P6T Deluxe (LGA 1366)
  • Intel Core i7 920 2.6Hz (4 physical cores), Hyper-threading on (8 logical cores)
  • 12 Gb RAM 1333MHz
  • Boost C++ Libraries 1.50 + все патчи из /asio_samples/build/patches/boost_1_50_0
  • Qt 4.8.2 static build with static C/C++ runtime + патчи из /asio_samples/build/patches/qt_4_8_1_patches: build_static_win32-msvc2010.patch, container_msvc_warn.patch, win_cursors.patch
  • Исходники asio samples из https://asio-samples.svn.sourceforge.net/svnroot/asio-samples/trunk (revision 617)
  • Проект echo_server, собранный в конфигурации Profile/Win32
  • Проект asio_performance_test_client, собранный в конфигурации Profile/Win32

Тестирование echo_server (echo_server120719.vsps).
  • Параметры запуска echo_server (echo_server.psess):
    --port=7 --inactivity_timeout=60 --session_threads=4
  • Параметры запуска asio_performance_test_client:
    127.0.0.1 7 4 4096 10000 600 0

Тестирование asio_performance_test_client (asio_performance_test_client120719.vsps).
  • Параметры запуска asio_performance_test_client (asio_performance_test_client.psess):
    127.0.0.1 7 4 4096 10000 600 0
  • Параметры запуска qt_echo_server (кроме тех, чьи значения по умолчанию не менялись):
    Execution/Session (IO) threads: 4; Session management/Listen backlog: 10000; Session/Inactivity timeout (seconds): 60.

Буду постепенно дописывать данное сообщение. Пока выкладываю результаты как есть.

Немного поколдовал над результатами тестов: для исключения некоторых функций пришлось сделать выгрузку в Excel - echo_server120723.xls и asio_performance_test_client120723.xls (см. столбец "Elapsed Exclusive Time, fixed %").
Думал над функцией [<Unknown>] в отчете по asio_performance_test_client. Похоже, это ConnectEx - именно ее название компилятору неизвестно и именно ее вызывает функция ma::async_connect.

Updated 24.07.2012
Залил конфигурацию сборки проектов echo_server и asio_performance_test_client в SVN.
Обновил результаты тестов.
Добавил скорректированные таблицы результатов работы профилировщика в разрезе функций.

Updated 26.07.2012
Как видно из "скорректированных" таблиц результатов работы профилировщика, большую часть времени и echo_server и asio_performance_test_client проводят в системных функциях ввода-вывода (почему-то в WSASend - видимо, это связано с тем, что и сервер и клиент работали на одной и той же машине и общались через localhost) и демультиплексирования событий. По-моему, это хороший результат.

Думаю, стоит попробовать Intel VTune - интересует работа потоков.

Updated 11.08.2012
Попробовал погонять по сети и измерить VTune-ом (Core2 Duo E7200, Windows 7 x86 SP1 Pro, https://asio-samples.svn.sourceforge.net/svnroot/asio-samples/trunk@660):
Для большей наглядности почти те же данные в виде графиков:

Итоговый график для echo_server

Bottom-up для echo_server

Итоговый график для asio_performance_test_client

Bottom-up для asio_performance_test_client

Результаты, в общем-то, ожидаемо положительные и совпадают с отчетом "студийного" профилировщика. Единственное, что вызывает подозрение, это 2-х ядерный процессор. Я все еще ищу возможность использовать VTune на 8-ядерном процессоре (думаю, еще понадобится несколько n-ядерных машин, чтобы нагрузить такой сервер "под завязку").

суббота, 30 июня 2012 г.

Уязвимости серверов к медленному чтению

По мотивам старой статьи на habrahabr.

Когда я писал echo_server, этой статьи на Хабре еще не было. Но я думал о том, что клиент (remote peer) может «нарочно медленно» принимать данные. Именно поэтому я использую класс ma::cyclic_buffer, совмещающий в себе и буфер приема, и буфер отправки. Благодаря такому совмещению, мне, кажется, удалось более гибко распределить ресурсы сервера:
  • с одной стороны, я выставляю ограничение памяти (размер буфера) на всю сессию,
  • с другой – это ограничение динамически распределяется на буфер отправки и буфер приема одновременно, т.е. выделенное пространство используется максимально эффективно.
Кроме того, я реализовал таймаут. И не просто таймаут на отправку (хотя хватило бы и его), но совмещенный таймаут (+ сэкономил один таймер) «активности remote peer»:
в течение указанного для таймаута значения удаленный конец должен завершить хотя бы одну активную операцию ввода/вывода, если только таковая есть (еcли кому-то интересны подробности, спрашивайте в комментариях).
Конечно, это не полноценная защита. Но, IMHO, и сервер (middleware, application layer) надо проектировать так, чтобы минимизировать возможность проведения успешных атак (в т.ч. DOS) – в идеале вообще исключить их.

FAQ

Соберу-ка здесь некоторые полезные материалы по теме сокетов.

Начну с правильного завершения/закрытия TCP-сессии (сокета) с точки зрения Winsock (в Linux, полагаю, можно делать аналогично, т.е. данный подход одинаково хорошо сработает и в Windows и в Linux). Немногие статьи освещают эту тему. Почему-то закрытие TCP-сессии (равно как и останов сервера) часто обделяют должным вниманием.
Кому есть что добавить - милости прошу в комментарии.

Updated 2013/12/04:
RTFM: Йон Снейдер: "Эффективное программирование TCP/IP". Очень правильная книга, вправляющая мозги по поводу многих мифов вокруг TCP. Часто встречаю в сети (форумы, списки рассылок) вопросы, решаемые прямой отсылкой к соответствующей главе данной книги.

Updated 2019/03/13:
Asio, SSL, and scalability

Updated 2020/05/23:
Why does one NGINX worker take all the load?

воскресенье, 22 апреля 2012 г.

Немного новостей

Вышел очередной бета-релиз asio samples – 0.3.9.

Кроме исправления ошибок в этот релиз вошел сильно измененный Asio performance test client (проект asio_performance_test_client) из non-Boost версии Asio. Хотя данный тест, пожалуй, пригодится лишь для тестирования простейших серверов (TCP-echo/proxy), его отсутствие сильно «напрягало» – приходилось брать сторонние решения, которые работали не так, как ожидалось. Хотелось бы видеть этот тест и другие, связанные с ним, части asio samples в Boost версии Asio. Вот только с местом, куда скинуть предложение/исходники, я пока не определился – то ли на sf.net, то ли на github. Если последнее, то уместен был бы pull request, но, как я понимаю, для начала надо будет выкачать рабочую копию из своей branch, созданной на основе Asio master branch… лениво разбираться с git.

Кроме asio_performance_test_client я наконец-то довел до ума проекты для QMake – теперь есть возможность (скорее требование) указать локальную копию Boost, используемую для сборки. Для автоматической компоновки с Boost.Chrono (при наличии это библиотеки) пришлось почитать документацию к QMake :)

Не буду переписывать здесь release notes из списка рассылки asio-samples-users – добавлю лишь, что уже сегодня залил в trunk asio samples патч, заменяющий в Boost.Asio (Boost 1.49) все вызовы Win32 API InterlockedXXX на соответствующие макросы из boost/detail/interlocked.hpp. Почему автор Asio так и не перевел (см. мой вопрос в списке рассылки asio-users) Boost версию на эти макросы для меня остается загадкой (аргумент а-ля details/non-stable не принимается). Может ему просто лень настолько сильно разделять Boost и non-Boost версии?

среда, 30 ноября 2011 г.

Для "почитать"

Что-то зачастил я с подобными постами - но ведь интересно же, "как это делают люди".

Richard Jones: A Million-user Comet Application with Mochiweb, Part 3.
Even so, I think this could be generalized in such a way that would allow you to use Erlang for all the interesting stuff, and have a C+libevent process act as a dumb connection-pool. With a bit more wrapper code and callbacks into Erlang, you’d hardly need to know this was going on - the C program could be run as a driver or a C-node, and an Erlang wrapper could give you a decent api built on top of libevent.

Urban Airship Blog: C500k in Action at Urban Airship.
... we pressed on with a Java + Pure NIO implementation.

вторник, 11 октября 2011 г.

Чтиво

$3M инвестиций в NGINX.
Deep C (and C++) (сегодня запостили на RSDN) - каждый слайд, что называется, "в яблочко".
Overload 105 (см. Picking Patterns for Parallel Programs). Asio samples == almost C++ actors based on task based (fork/join) parallelism.

пятница, 30 сентября 2011 г.

Весёленький год

Мда. Этот год, наверное, поставил рекорд по остроте новостей с IT-фронта:
1. Nokia отвернулась от MeeGo и ищет спасения под крылом MS WP7
2. HP – рыба гниет с головы
3. Intel, что вы там курите? (комментарии особенно хороши)

Очень жаль, и Qt (в т.ч. соотв. подразделение Nokia) и MeeGo.

суббота, 10 сентября 2011 г.

timer revisited

В выложенной недавно версии 0.3.5 реализован "канонический" вариант работы с таймером (ma::echo::server::session). Данный вариант принципиально отличается от предыдущего (!). В прошлом я намеренно сужал API asio::deadline_timer до Java-вского ScheduledExecutorService, дабы иметь в кармане решение и для Java. Однако, с asio::deadline_timer можно работать эффективнее.

Нужно заметить, что мой варинт отличается от того, что предложил автор Asio:
1. нет таких "подвывертов", как deadline_.expires_at(boost::posix_time::pos_infin);
2. нет явных обращений к now(): deadline_.expires_at() <= deadline_timer::traits_type::now().
3. все обыгрывается за счет двух булевых флагов - их можно было заменить одной переменной с тремя состояниями, но с флагами получилось читабельнее.

P.S. А для ScheduledExecutorService можно сделать все в точности так же и никакого "сужения" не нужно было вовсе 8)

понедельник, 5 сентября 2011 г.

echo_server revisited

Наконец-то закончен "канонический вариант" активного объекта - ma::echo::server::session и ma::echo::server::session_manager.

Единственное по-настоящему важное изменение – это введение явных раздельных state machine (КА) для внешней части активного объекта (proxy) и для внутренней части (implementation). Так же явно введены КА для каждого вида internal activities. При этом код стал визуально чище и проще (на днях заглянул в код Qt - бр-р-р).

Удалось обойтись без Boost.MSM. Пока я не вижу, чем могла бы помочь данная библиотека, т.к. налицо несколько взаимосвязанных КА, либо какой-то combinatorial FSM.

P.S. Из-за загруженности на основной работе впопыхах пропустил пару глупых ошибок как в коде/логике, так и в комментариях – поэтому текущая версия уже 0.3.5.

Золотые слова

Цитата из этой статьи с Хабра:
На самом деле, принятие гибридного подхода к параллелизма, кажется, является движением вперед, если нет каких-либо противопоказаний. Ученые в области компьютерных наук из университета штата Пенсильвания обнаружили, что сочетание потоков и событий предлагает лучшее из обоих миров. Команда Scala в EPFL утверждает, что Actors объединяют программирование на основе потоков выполнения и программирование на основе событий в одну аккуратную, простую для понимания, абстракцию. Russ Cox, бывший сотрудник Bell Labs, теперь занятый проектом языка программирования Go в Google, заходит ещё дальше, утверждая, что бессмысленна сама дискуссия „потоки против событий“ (обратите внимание, что все это даже не затрагивает аспект распределения масштабирования системы; потоки — это конструкции для одного компьютера, и события, — конструкции для одного процессора; мы даже не говорим о распределении работы между машинами в простой манере; кстати, это включено в Erlang, и о нём стоит задуматься, если вы няньчите быстро растущую систему).
Именно к active object/actor (на уровне, максимально облегченном в плане прослоек) я и стремлюсь. Кто-нибудь может сравнить echo_server с Erlang-style в плане параллелизации? И что это за проект на китайском?

воскресенье, 24 июля 2011 г.

Re: The last of the Boostcon videos

Наконец-то я полностью посмотрел последний доклад Christopher Kohlhoff Why C++0x is the Awesomest Language for Network Programming на BoostCon 2011. До этого я лишь бегло пробежался по нему и сделал вывод, что ничего нового там для меня нет.

И действительно, все, что прозвучало в докладе, давно есть в блоге автора и в Boost.Asio 1.5.3 (а теперь и в Boost 1.47). Подумать только, stackless coroutines были анонсированы (dev версия, так и не вошедшая в Boost.Asio) еще в 2009 году, а о поддержке move semantic для completion handlers я просил еще с момента прочтения статьи Onward, Forward! Dave Abrahams (и реализовал ее в asio samples раньше, чем она официально появилась в Boost.Asio). Но как же здорово, что есть возможность почти вживую послушать автора и его комментарии к исходному коду (а заодно и оценить юмор как самого автора, так и его слушателей). Спасибо, Marshall Clow. Появились бы эти (известные всем подписчикам рассылок по Boost) видеозаписи докладов, если бы не он?

Что ж, BoostCon 2011 закончен. Сенсаций от автора Asio не прозвучало. Да и нужны ли они на таком мероприятии? Скорее "нет", чем "да". Судя по тем немногочисленным вопросам из зала, рассказать слушателям про возможности Boost.Asio было все же важнее. Теперь ждем BoostCon 2012 и надеемся вновь увидеть автора Asio. Учитывая объем изменений, вошедших в Boost 1.47, можно сказать, что Boost.Asio активно развивается (ну или точно не стоит на месте). Значит, Крису будет о чем рассказать нам в следующий раз. Может стоит предложить ему несколько тем? Я мог бы предложить рассказать подробнее о custom memory allocation и соответствующих hook-функциях для привязки к handler. Или раскрыть тему asio_handler_invoke. А Вы?

четверг, 7 июля 2011 г.

Client-side Boost.Asio: быть или не быть? ;)

Предлагаю читателям обсудить в комментариях к этому сообщению следующую тему: стоит ли использовать Boost.Asio на стороне клиента. С серверами все понятно - там вменяемой альтернативы (на C++) нет. А вот с клиентами как?

Для "затравки" мое мнение: то, что клиенты до сих пор не используют асинхронный ввод/вывод - "дело времени" и связано с привычкой и ленью.
Да, можно выделить весь синхронный ввод-вывод в отдельный поток (thread). Но (!) как Вы собираетесь передавать данные в этот поток и получать данные из него? Конечно же через очереди. Ага, получаем как раз тот вариант (io_service + io_service::strand), что описан в проекте nmea_client. Т.е. без Asio это будет просто очередной "велосипед".

Я могу ошибаться. Мне очень интересны (контр)аргументы противоположной стороны. Буду рад их услышать и сделать какие-то выводы для себя.