вторник, 27 ноября 2007 г.

Новая версия библиотеки act-o

После достаточно продолжительного перерыва, я рад сообщить, что выложил новую версию библиотеки act-o.

Надо сказать, что до этого на sourceforge.net находилась концептуальная версия библиотеки – у ней был проработан интерфейс, можно было описывать взаимодействие актеров, можно было запускать программы на ее основе, но библиотека не могла продолжительное время работать под нагрузкой. Данный же релиз обладает полноценной средой выполнения (runtime) и планировщиком потоков.

Особо важным считаю тот факт, что в то время как среда выполнения была почти полностью переработана, интерфейс библиотеки остался неизменным. Это означает, что летний – проектный этап был успешным. Хотя некоторые косметические изменения все же пришлось внести.
  • Изменился заголовочный файл, который необходимо подключать, чтобы воспользоваться библиотекой – вместо «act_o.h» теперь необходимо подключать «multiprog.h».
  • Переименовано пространство имен – вместо act_o теперь необходимо писать acto (без подчеркивания).
  • Были добавлены две обязательные функции, которые необходимо явно вызывать acto::startup – инициализация библиотеки и acto::shutdown – закрытие библиотеки и освобождение всех ресурсов.
Возможности среды выполнения

Новая реализация runtime’а обладает следующими характеристиками:
  • Позволяет указывать объекты, сообщения для которых будут обрабатываться в отдельном потоке (эксклюзивные объекты) и объекты, потоки под которые будут распределяться автоматически (управляемы объект).
  • Подстраивается под загруженность системы и может выделять дополнительные потоки под управляемые объекты, если текущие потоки не справляются с обработкой всех сообщений. Это позволяет продолжать обработку сообщений, даже если часть объектов выполняет сверхдолгие или блокирующие операции. В данной версии установлено ограничение на максимальное число потоков – 512.
  • Автоматически удаляет излишние потоки, выделенные под управляемые объекты, при уменьшении нагрузки на систему.
  • Использует подсчет ссылок для определения того момента, когда объект можно удалять, но так как большинство объектов имеют ссылки на самого себя, то необходимо явно указывать момент удаления объекта с помощью функции acto::destroy. Однако следует отметить, что такой механизм не порождает проблем с повисшими ссылками, так как я позаботился о том, чтобы заголовок объекта удалялся только тогда, когда на него больше не остается ссылок. Некоторые причины такого способа управления объектов я описал ранее в своей заметке «Необходимость сборки мусора в многопоточных программах».
Тест работоспособности

Для того чтобы убедиться, что среда выполнения работает исправно, я провел тест на основе программы «ping pong», которая поставляется вместе с библиотекой. Вы также можете запустить ее у себя и сравнить результаты.

Тестирование проводилось со следующими параметрами: 50000 активных объектов, 50000 одновременно пересылаемых сообщений, 50 циклов start/stop в каждом из которых по 50 циклов активного обмена сообщениями. Код, который выполнялся в данном тесте, можно посмотреть, загрузив пакет библиотеки act-o, в файле «samples/ping-pong/main.cpp».

Тестовая платформа: ASUS P5K-VM, Intel Core Duo E2180, 2GB – DIMM PC-5300 DDR II, Windows XP x64 Pro.

Были получены следующие результаты – на ненагруженной машине средний показатель производительности составил 400’000 сообщений/сек. При тестировании было замечено, что среда выполнения не очень устойчива к сверхбольшой нагрузке – больше 100’000 активных объектов и больше 100’000 одновременно пересылаемых сообщений. Конечно, программа не падает, но работает очень медленно и в заданный интервал времени не успевает обработать все сообщения. Я думаю, что это в основном связано с отсутствием специально адаптированного менеджера памяти. Также в текущем алгоритме планирования есть вероятность избыточного расходования системных потоков – данный эффект может проявляться при очень плотном потоке сообщений.

Использование и дальнейшее развитие

На данный момент я применяю библиотеку act-o для создания серверных приложений. Если быть точнее, то для программирования асинхронной работы внутри сетевых серверов. Это позволяет мне легко организовать асинхронное взаимодействие между объектами приложения в случае использования неблокирующих сокетов.

Библиотека сетевых компонентов находится на ранней стадии производства и еще сложно сказать насколько может различаться производительность приложений сделанных на основе act-o и приложений, где многопоточность реализуется «руками». Пока что могу выразить только свое субъективное впечатление по поводу упрощения организации асинхронного взаимодействия между объектами и избавления от проблем с разделяемой памятью – ну почти как в Erlange… ;-)

Касательно планов дальнейшего совершенствования библиотеки act-o, то в первую очередь, я хочу снабдить ее полноценным многопоточным менеджером памяти, и добавить некоторые дополнительные возможности. Некоторые из них уже разработаны – например, таймер, который может посылать другим пользовательским объектам сообщение msg_time через указанные промежутки времени. В данный же релиз библиотеки он не включен потому, что его интерфейс еще недостаточно продуман и могут быть внесены изменения, которые сделают его несовместимыми с предыдущими версиями.

В более отдаленных планах еще раз переписать runtime уже на основе более проработанной модели планирования обработки сообщений и, возможно, снабдить его алгоритмом сборки мусора. Как и обычно менять интерфейс библиотеки при этом не планируется. Только возможно, что удастся избавиться от явного удаление объектов функцией acto::destroy, или как минимум сделать ее необязательной.

Вообщем, буду рад узнать, если библиотека act-o поможет вам при разработке ваших приложений. Со мной всегда можно связаться через этот блог, или написать прямо по почте – адреса можно найти в профиле или в заголовках к коду библиотеки.

вторник, 4 сентября 2007 г.

Рандеву – концепция параллельного программирования

Изучая концепции параллельного программирования, приходится часто сталкиваться с такой концепцией как «рандеву». Многие упоминают ее, говорят, что на основе этой концепции построена модель параллелизма в языке Ada, но как-то мне не довилось еще встретить материал, в котором рассказывалось бы о сути рандеву. Поэтому я решил восполнить пробел, в первую очередь в своих знаниях, но надеюсь, что вам это тоже будет интересно и полезно.

Коль скоро рандеву – это основная концепция организации межпроцессного взаимодействия в языке Ada, то в поисках ответ о том, что такое рандеву, я решил обратиться, что называется, к первоисточникам. В ru-нете есть сайт по языку Ada, где я обнаружил книгу, в которой излагается суть механизма рандеву и принципы его описания в языке. Книга называется «Адское программирование» и в «главе 15: Многозадачность» описывается идея рандеву. Процитирую ту часть, в которой описывается суть термина, а за подробностями и разъяснениями предлагаю обратиться к самой книге.

Как один из механизмов обеспечения надежного межзадачного обмена данными и взаимной синхронизации работы задач, Ада предоставляет механизм рандеву.
Основополагающая идея механизма рандеву достаточно проста. В спецификации задачи публикуются различные входы (entry) в задачу, в которых она готова ожидать обращения к ней от других задач. Далее, в теле задачи указываются инструкции принятия обращений к соответствующим входам, указанным в спецификации этой задачи.

Необходимо обратить внимание на несимметричность такого механизма взаимодействия. Это означает, что в процессе взаимодействия одна из задач рассматривается как сервер, а вторая - как клиент, причем задача-сервер не может быть инициатором начала взаимодействия.

В простейшем случае, когда рассматривается взаимодействие только двух задач, задача-клиент, желающая обратиться к другой задаче (задаче-серверу), инициирует обращение к входу задачи-сервера. После этого задача-сервер откликается на обращение задачи-клиента, принимая обращение к этому входу. Таким образом, взаимодействие двух задач осуществляется в ситуации, когда задача-клиент обратилась к входу, а задача-сервер готова принять это обращение. Этот способ взаимодействия двух задач называется рандеву.

Поскольку задача-клиент и задача-сервер выполняются независимо друг от друга, то нет никакой гарантии, что обе задачи окажутся в точке осуществления рандеву одновременно. Поэтому, если задача-сервер оказалась в точке рандеву, но при этом нет ни одного обращения к входу (запроса на взаимодействие), то она должна ждать появления такого обращения. Аналогично, если задача-клиент обращается к входу, а задача-сервер не готова обслужить такое обращение, то задача-клиент должна ждать, пока задача-сервер обслужит это обращение. В процессе ожидания, как задача-клиент, так и задача-сервер не занимают ресурсы процессора, находясь в состоянии, которое называют приостановленным или состоянием блокировки.


Если внимательно почитать вышеуказанную книгу, то можно узнать, что рандеву, как и модель актеров, предлагает изолировать состояния процесса (объекта). И изменять его только в специальных точках взаимодействия. Только рандеву осуществляет синхронный механизм взаимодействия, в то время как сообщения – предоставляют асинхронный механизм.

В следующий раз расскажу о том, как я, пытаясь реализовать взаимодействие между потоками в ядре библиотеки act-o, естественным путем пришел к точно такой же идее взаимодействия как рандеву, еще до того, как познакомился с вышеизложенным материалом.
Оставайтесь на связи… :-)

воскресенье, 2 сентября 2007 г.

И все-таки она необходима

Стоило только мне вынести предыдущую заметку на один форум, как оказалось, что:
  1. Сборка мусора необходима не только в многопоточных программах, но и в компонентном программировании.
  2. Существует статья, в которой предпринята попытка доказать необходимость автоматического управления памятью в компонентных программах.
Конечно, это вопрос еще предстоит проработать более подробно применительно именно к многопоточному программированию, но думаю, что общий ответ явно не вызывает сомнения – автоматическое управление памятью (сборка мусора) необходимо в системах с массовым параллелизмом.