пятница, 10 июня 2011 г.

Не пропадать же зря...

На днях просматривал forum.vingrad.ru.

Вспомнил, что в свое время я оставил один развернутый комментарий. "Развернутый" специально для дальнейшего использования в моих новых сообщениях/статьях о Boost.Asio.

Статей до сих пор нет, а тема "горячая" (ёпрст, многие, кто использует Asio, до сих пор не знают этого. Я бы вообще не стал использовать Asio, не будь в нем такой возможности, так как в этом случае raw-C-written-WinSock-based сервер давал бы ощутимое превосходство в скорости) - так что приведу выдержку из того комментария здесь:

Могу только пояснить следующее: как любая система построенная по шаблону Proactor (да и вообще - как все многопоточные системы, базирующиеся на очередях - т.е. почти все более-менее "продвинутые" многопоточные системы, например, Intel TBB), asio активно использует очереди (в случае asio - это очереди из функциональных объектов).

В связи с этим остро встает вопрос выделения памяти в таких очередях (особенно остро в свете многопоточности и кешей процессора). Intel TBB решает это своим "прокаченным-специализированным" аллокатором (и обещаниями повторно использовать выделяемые блоки).

asio использует очень легкое и гибкое решение (и это не единственный случай!): позволяет использовать allocator per async operation (начиная с dev release 1.53 - во всех асинхронных операциях). И вот какая штука: в любом вменяемом (т.е. не "hello world") приложении количество одновременных однотипных асинхронных операций над одним и тем же объектом (например, socket или deadline_timer) всегда ограничено сверху. И зачастую это ограничение равно единице (Вы уже на него нарвались недавно).

Исходя из всего вышесказанного, зачастую, Вы можете просто заранее выделить непрерывный блок памяти, который будет удерживаться Вашим handler-ом (например, при помощи shared_ptr). Затем, каждый раз когда asio будет нужна память для чего-то временного (обычно, это память для расположения в очереди - IOCP или boost::asio::io_service::strand или даже deadline_timer), что связанно с асинхронной операцией, для которой Ваш handler является completion handler-ом - asio просто попросит об этом через Ваш же handler. При этом те гарантии что дает asio относительно custom memory allocation, гарантируют, что (при достаточном размере Вашего пред-аллоцированного блока памяти) Вы всегда сможете выделить эту память из того самого, ранее выделенного, блока памяти.

Кроме того, гарантии asio позволяют удерживать этот "пред-аллоцированный блок памяти" самим же handler-ом (с небольшим ограничением на handler - см. доки по Boost.Asio 1.53, почти всегда это ограничение выполняется и уж точно всегда его можно легко обойти). Главное, хранить в handler-е не сам блок, а указатель на него (лучше -smart) - чтобы в блок помещался сам handler + что-то временное.

В моем проекте (http://sourceforge.net/projects/asio-samples) echo_server (и qt_echo_server, и, вообще, все "asio samples") вообще не выделяет память в куче при своей непосредственной работе (кроме приема новых входящих TCP-соединений, да и тут есть reuse). Custom memory allocation сводит все выделения памяти к тому коду, что я указал - т.е. никаких блокировок и даже никаких атомарных (interlocked) операций. Плюс, в теории (не могу до сих пор проверить) - это должно очень положительно сказаться на использовании CPU-кеша (Updated: и на branch prediction) (+ учтите очень правильную реализацию strand-ов в asio).

В дополнение:
  • см. ma/context_alloc_handler.hpp, ma/custom_alloc_handler.hpp и ma/handler_allocator.hpp (это практически copy-paste из примеров Chris-а и из private/details-"внутренностей" Boost.Asio, так что все лавры направляйте в сторону автора Asio).
  • см. документацию по Asio Custom Memory Allocation.

P.S. Комментарии и даже "холивар" приветствуются.

3 комментария:

niXman комментирует...

"Не пропадать же зря..."
однозначно, нет!

со всем согласен. в теории. на практике же..ну...тут основная сложность в усваивании кода из asio_samples.
от себя, скажу следующее: я, будучи не новичком, все же испытываю серьезные сложности при разборе asio_samples. и основная сложность не в том, что языка/шаблоннов/паттернов не знаю.. - сложность в том, что примеры не сопровождаются хотя бы минимальными пояснениями вроде: "в этом примере я покажу использование таких-то и таких-то приемов..", "этот класс используется для того-то и для того-то". все. подобные комменты не расписывают каждую строку кода, но они позволяют акцентировать внимание на то, что пример демонстрирует.

спасибо.

Marat Abrarov комментирует...

примеры не сопровождаются хотя бы минимальными пояснениями

Комментариям быть! 8)

А если серьезно, то я уже переформатировал весь код согласно Boost style guide (а еще переименовал кое-что и кое-что подправил/улучшил).

К сожалению, плохо продвигается дело с переписыванием логики session_manager/session (я имею в виду только внутреннюю логику - все никак не получается написать правильные КА и или их совокупность). Это до сих пор оттягивало комментарии.

Но вот уже неделя, как "принято решение" написать комментарии для устоявшихся классов/файлов. Таковыми являются все классы в пространстве имен ma (но не во вложенных в него пространствах имен).
Комментарии планируются а-ля Boost.Asio (т.е. с использованием режима "подсмотрел-написал-аналогично"), дабы оперировать теми же терминами.

Впереди 3 выходных - думаю, обещанные комментарии набросаю.

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

niXman комментирует...

огромное спасибо за Ваше время.
жду с нетерпением :)