пятница, 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 комментирует...

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

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

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

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

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

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

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

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

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