Пиши Дома Нужные Работы

Обратная связь

Аспектно-ориентированное программирование

Аспектно-ориентированное программирование (АОП) — парадигма программирования, основанная на идее разделения функциональности для улучшения разбиения программы на модули. Методология аспектно-ориентированного программирования была предложена группой инженеров исследовательского центра Xerox PARC под руководством Грегора Кичалеса (Gregor Kiczales). Ими же был разработан аспектно-ориентированное расширение для языка Java, получившее название AspectJ — (2001 год).

Существующие парадигмы программирования, такие как процедурное, модульное и объектно-ориентированное программирование, предоставляют определённые способы для разделения и выделения функциональности (функции, классы, модули), но некоторую функциональность с помощью предложенных методов невозможно выделить в отдельные сущности. Такую функциональность называют сквозной ( scattered, разбросанная или tangled, переплетённая), так как её реализация рассыпана по различным модулям программы. Сквозная функциональность приводит к рассредоточенному и запутанному коду, сложному для понимания и сопровождения.

Все языки АОП предоставляют средства для выделения сквозной функциональности в отдельную сущность. Так как AspectJ является родоначальником этого направления, используемые в этом расширении концепции распространились на большинство языков АОП. Основные понятия АОП:

• Аспект ( aspect) — модуль или класс, реализующий сквозную функциональность. Аспект изменяет поведение остального кода, применяя совет в точках соединения, определённых некоторым срезом.

• Совет ( advice) — средство оформления кода, который должен быть вызван из точки соединения. Совет может быть выполнен до, после или вместо точки соединения.



• Точка соединения ( join point) — точка в выполняемой программе, где следует применить совет. Многие реализации АОП позволяют использовать вызовы методов и обращения к полям объекта в качестве точек соединения.

• Срез ( pointcut) — набор точек соединения. Срез определяет, подходит ли данная точка соединения к данному совету. Самые удобные реализации АОП используют для определения срезов синтаксис основного языка (например, в AspectJ применяются Java-cигнатуры) и позволяют их повторное использование с помощью переименования и комбинирования.

• Внедрение ( introduction, введение) — изменение структуры класса и/или изменение иерархии наследования для добавления функциональности аспекта в инородный код. Обычно реализуется с помощью некоторого метаобъектного протокола ( metaobject protocol, MOP).

Ведение лога и обработка ошибок — типичные примеры сквозной функциональности. Другие примеры: трассировка; авторизация и проверка прав доступа; контрактное программирование (в частности, проверка пред- и постусловий). Для программы, написанной в парадигме ООП, любая функциональность, по которой не была проведена декомпозиция, является сквозной.

Однако как утверждают некоторые авторы, АОП может успешно применяться и для решения задач защиты, многопоточности, управления транзакциями и многих других.

 

Контрольные вопросы

 

1. Дайте понятие парадигмы программирования.

2. Может ли язык программирования поддерживать сразу несколько парадигм?

3. Охарактеризуйте процедурное программирование?

4. Охарактеризуйте функциональное программирование?

5. В чем особенность логического программирования?

6. Что такое автоматное программирование?

7. В чем особенность объектно-ориентированного программирования (ООП)?

8. Какой язык был первым в ООП и когда он появился?

9. Какое понятие является важнейшим в ООП?

10. Поясните основные принципы ООП?

11. Перечислите родственные ООП методологии.

12. От какого принципа отказались в прототипном программировании?

13. Какие особенности ООП приводят к снижению производительности программных систем?

14. Охарактеризуйте обязательный набор синтаксических средств объектно-ориентированного языка программирования.

15. В чем заключается аспектно-ориентированное программирование?

Глава 12. Эффективность и оптимизация программ

Общие понятия эффективности

 

Основной задачей программирования является создание пра­вильных, а не эффективных программ. Эффективная программа не нужна, если она не обеспечивает правильных результатов. Это правило Ван Тассела. Эффективная, но неправиль­ная программа редко может быть сделана правильной, в то время как правильную, хотя и неэффективную программу можно опти­мизировать и сделать эффективной. Поэтому оптимизация являет­ся вторым этапом программирования. Первый этап — получение правильной программы.

Наиболее разумный подход к программированию заключается в создании программы наилучшим возможным способом, не уделяя особого внимания эффективности. Затем, если

  • программа в таком виде пригодна,
  • если она нужна для работы,
  • если ее будут выпол­нять многократно и
  • если статус проекта и фирмы позволяет,

тогда и только тогда следует рассмотреть возможность ее оптимизации.

Обыч­но большая часть времени расходуется на выполнение очень небольшой части программы (<~5% ее объема), называемой крити­ческой областью. Как правило, только критическая область объ­ектной программы оптимизируется программистом вручную. Погоня за эффективностью часто ведет к злоупотреблению. За­мечено, что программисты тратят огромное количество времени, думая и беспокоясь о работе некритических областей программы. Современные компьютеры отличаются высоким быстро­действием и очень мала разница во времени выполнения програм­мы, если некоторые, редко выполняемые операторы удается сде­лать эффективными. Экономию можно получить только за счет многократно выполняемых циклов.

Некоторые программисты считают архаичной задачу написания эффективной программы. Это справедливо только в отношении не­больших программ, для выполнения которых используются ма­шины с высоким быстродействием и большим объемом памяти. Что же касается больших программ, то еще на стадии проектиро­вания определяются требуемые параметры, включающие время и емкость памяти. Для экономических задач емкость памяти часто более критичный параметр, чем время. Создатель системного программного обеспечения должен установить не­обходимые объем памяти и производительность каждого модуля, особенно при создании боль­ших программных проектов. Требования к эффективности программы определяются на стадии проектирования.

Существуют три типа программ, и для каждого из них эффек­тивность должна быть различной.

К первому типу относятся часто используемые программы. Это операционные системы, компиляторы, прикладные подпрограммы и системы резервирования авиабилетов. Для этих программ эф­фективность является первостепенной задачей вследствие их ча­стого использования и специфического выполнения.

Второй тип составляют производственные программы, исполь­зуемые длительное время. Этот тип программ пишут профессио­нальные программисты. Хотя эффективность таких программ су­щественна, обычно еще больше внимания уделяют их эксплуатаци­онным характеристикам.

Третий тип программ—программы, созданные не программи­стами, а научными работниками или администраторами. Время для этих людей важнее всего. Здесь эффективность имеет значение только для программ, которые должны уместиться в заданном объеме памяти и выполняться за приемлемое время.

Следовательно, еще до написания программы необходимо уста­новить, насколько эффективной она должна быть. Очевидно, что следует модифицировать только те программы, которые выполня­ются многократно. Программисты, «экономящие на спичках», со­кращают на 10 мкс время выполнения редко используемой прог­раммы, затрачивая при этом 2 ч на программирование и много минут на компилирование и тестирование. Очевидно, что в этом случае вы ничего не сэкономите. Зато, как и при любом изменении программы, можете добавить в нее ошибки. Однако человеческая натура такова, что эффективность программ всегда будет вызы­вать интерес.

Многие методы, делающие программу эффективной, не наносят ущерба ее удобочитаемости. Эти методы следует использовать всегда. Но некоторые меры по повышению эффективности могут быть просто вредными для по­лучения удобочитаемой программы. Удобочитаемость программы более существенна, чем ее эффек­тивность. Дело в том, что удобочитаемую программу легче отла­живать, модифицировать и использовать. А всякую большую про­грамму обычно изменяет, модифицирует и применяет совсем не тот человек, который ее писал. Лишь в особых случаях программу следует делать более эффективной: программа: либо не помещается в памяти, либо слиш­ком долго выполняется. Или же программа должна быть включена в библиотеку и часто использоваться. В этом случае эффективность становится очень важным фактором и ей отдают предпочтение в ущерб удобочитаемости.

Оптимизирующие компиляторы

 

Эффективность важна на двух стадиях разработки програм­мы: компилирования и выполнения. Если компилятор работает быстро, то он обычно составляет программу, которая выполняется медленно. Компиляторы, создающие эффективную объектную про­грамму, обычно бывают большими и работают медленно, так как оптимизируют объектную программу.

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

К сожалению, об увеличении скорости компилирования можно сказать немного. Некоторые программные ухищрения могут со­кратить время компилирования, но они либо тривиальны, либо сильно зависят от компилятора. Методы, дающие положительный результат при использовании в одном компиляторе, не дают тех же улучшений в другом компиляторе. Некоторые компиляторы работают более эффективно, если дли­ны имен переменных распределены равномерно. Другие компиля­торы более эффективны, если метки операторов равномерно рас­пределены по последнему символу. Естественно, что исключение неиспользуемых меток и выражений также уменьшает время ком­пилирования любого компилятора. Наличие меток препятствует некоторым типам оптимизации, поэтому неиспользуемые метки ухудшают эффективность объектной программы. При повторном прогоне программы следует исправить все ошибки в исходной про­грамме, а число предупреждающих диагностических сообщений должно минимизироваться каждый раз, когда это возможно.

Описанные методы оптимизации не зависят от машины и применяемого языка и пригодны для оптимизации времени выполнения и мини­мизации объема памяти компилируемых программ. Эти методы машинно-независимы, так как улучшения, сделанные в программе с их помощью, приведут к ускорению работы программы на раз­ных машинах. Методы не зависят от языка (за исключением ме­тодов, специфичных для определенного языка) в том смысле, что они применимы в общем случае для языков высокого уровня. Не­которые из этих методов при их реализации на одних машинах бу­дут давать более заметные результаты, чем на других. Даже различные модели одной и той же машины могут иметь разные наборы команд ассемблера, которые обусловят заметную разницу в оптимизации.

Некоторые компиляторы оптимизируют выполнение программы. Имеются два типа такой оптимизации: машинно-зависимая и ма­шинно-независимая.

К первому типу относятся способы, результат применения которых зависит от используемой машины. Как пра­вило, эти способы оптимизации обычно не известны или не понят­ны программистам на уровне входного языка. Они состоят из спо­собов обработки индексов, назначения регистров и анализа ма­шинных команд.

Второй тип оптимизации — машинно-независимая оптимиза­ция,— которая выполняется на уровне входного языка. Хотя ком­пилятор может оптимизировать программу, но обычно у програм­миста большие возможности для этого. Многие способы оптими­зации может сделать только программист, так как они требуют знания логики программы. Некоторые способы оптимизации, вы­полняемые компилятором, могли бы быть применены, но не реа­лизуются просто потому, что требуют слишком много машинного времени. Таким образом, программисты, создающие программы, могут сделать очень много для оптимизации своих программ.

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

 

Оптимизация программ

 

Часто возникает необходимость в оптимизации некоторой рабо­чей программы, потому что, либо она выполняется слишком долго, либо для нее требуется слишком большой объем памяти. Вполне возможно, что при создании программы не думали о том, часто ли ее будут использовать, и не позаботились о ее эффективности. Или в результате значительной модификации программа стала неэффективной, а теперь она используется довольно часто и зани­мает слишком много машинного времени или, возможно, близка к превышению объема памяти, имеющегося в ее распоряжении. Поэтому нужно попытаться сделать программу более эффективной.

Если программу следует оптими­зировать, необходимо прежде всего тщательно проверить алгоритм. Основными критериями при этом должны являться время и объем памяти, ис­пользуемые программой. Если оптимизация старого алгоритма не дает желаемого ре­зультата, тогда, возможно, следует выбрать другой алгоритм. В дальнейшем предполагается, что первоначальный алгоритм обос­нован и целесообразен, однако программисты, которым нужно оп­тимизировать свою программу, никогда не должны делать такого предположения.

Сегментация программ

Программу, подлежащую оптимизации, следует разделить на подпрограммы. Оптимизация значительно облегчается, если про­грамма уже разделена на подпрограммы в соответствии с принци­пами структурного программирования. Как только подпрограммы выделены, следует ответить на три вопроса:

  • Какой процент общего времени использует каждая подпро­грамма?
  • Насколько (в процентном выражении) оптимизируется каж­дая подпрограмма?
  • Сколько человеко-часов необходимо для достижения этой цели?

Каждый из этих вопросов подробно обсуждается далее.

Время работы подпрограмм

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

Если для определения времени работы каждой подпрограммы используются оценки и предположения, то часто возникают ошиб­ки и оптимизировать программу не удается. Поверхностные иссле­дования приведут к тому, что для оптимизации будут выбраны не те подпрограммы. После того как установлено фактическое время работы, подпрограмма, которая используется больше других, должна оптимизироваться в первую очередь. Предположим, что программа разделена на четыре подпрограммы и время их выпол­нения составляет для

подпрограммы А — 5%, подпрограммы С — 15%,

подпрограммы В — 60%, подпрограммы В — 20%.

Очевидно, что, даже если подпрограмму А исключить совсем (что, вообще говоря, невозможно), мы смогли бы сэкономить толь­ко 5% общего времени работы программы. Таким образом, попыт­ку оптимизации, вероятно, следует предпринять в первую очередь в отношении подпрограммы В, где возможна наибольшая эконо­мия.

Если нельзя получить фактическое время выполнения каждой подпрограммы, применяется другой подход, заключающийся в под­счете количества операторов в подпрограмме, используя листинг программы на входном языке высокого уровня. Операторы, вклю­ченные в тело цикла, следует учитывать многократно. Подсчет ко­личества операторов — достаточно надежный показатель времени, требуемого для каждой подпрограммы, но определение фактичес­кого времени работы подпрограммы гораздо лучше.

Большинство программ имеет одну критическую точку, которая использует большую часть времени выполнения. Нередко ка­кая-либо малая часть программы расходует более 50% времени выполнения. Очевидно, что эту часть программы следует оптими­зировать в первую очередь.

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






ТОП 5 статей:
Экономическая сущность инвестиций - Экономическая сущность инвестиций – долгосрочные вложения экономических ресурсов сроком более 1 года для получения прибыли путем...
Тема: Федеральный закон от 26.07.2006 N 135-ФЗ - На основании изучения ФЗ № 135, дайте максимально короткое определение следующих понятий с указанием статей и пунктов закона...
Сущность, функции и виды управления в телекоммуникациях - Цели достигаются с помощью различных принципов, функций и методов социально-экономического менеджмента...
Схема построения базисных индексов - Индекс (лат. INDEX – указатель, показатель) - относительная величина, показывающая, во сколько раз уровень изучаемого явления...
Тема 11. Международное космическое право - Правовой режим космического пространства и небесных тел. Принципы деятельности государств по исследованию...



©2015- 2024 pdnr.ru Все права принадлежат авторам размещенных материалов.