TURBO PASCAL

Новости

Программы   

Turbo Pascal 

Игры

Документация   

Странности

FAQ

Ссылки

Форум

Гостевая книга

Рассылка

Благодарности

Об авторе

 

 

Процедуры и функции:

в чем смысл существования, как улучшается исполнимый код, на чем и как может сэкономить программист, и что ему может в этом помочь. Выводы.

В подготовке данного материала автор в значительной степени использует идеи, а метами и текст, принадлежащий В.В.Войтенко, в частности, главу 2 его учебника по ООП на С++.

Цели структуризации

 

На одном из предыдущих уроков было расказано, что можно выделять в процедуры и функции и какие при этом можно преследовать цели. Рассмотрим цели (совокупности целей), которые наиболее эффективно преследовать при структуризации программ на ЯП высокого уровня. Их можно объединить в две группы

  1. оптимизация параметров конечного (исполняемого) кода программы;
  2. оптимизация затрат на разработку программы.

 

Естественным, было бы всегда отдавать предпочтение только первой группе целей. Однако, как будет показано ниже, изначальное следование второй группе целей может привести к выполнению (части) целей первой группы.

Параметры кода

 

Оптимизация параметров кода есть выбор компромисса между его объемом и скоростью выполнения. Методам увеличения производительности программ не касающимся структуризации кода посвящены несколько уроков (см. оглавление); в данный момент остановимся на аспектах структуризации кода. Выделение повторяющихся участков кода в процедуры/функции приводит к увеличению времени выполнения и уменьшению объёма кода. Замеделение, появляющееся при создании процедур складывается из следующих трех составляющих:

  1. затраты на выталкивание параметров в стек и создание стекового фрейма под локальные переменные;
  2. затраты на непосредственный вызов и возврат из процедуры;
  3. затраты на косвенное обращение к параметрам, передаваемым по ссылке.

 

В случае, если объем исходного текста процедуры превышает десять строк, время на выполнение вызова/возврата из процедуры составляет (в среднем) не более 4%, а при увеличении объема процедуры - соответственно меньше. Следовательно, ускорение за счет многократного включения кода процедуры/функции в основную программу не превышает этих четырех процентов, тогда как проигрыш в объеме кода - многократный.

Отсюда естественный вывод: если программа не особо критична ко времени выполнения (не до наносекунд), то всегда следует отдать предпочтение уменьшению исходного кода (1).

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

Время программиста

 

Экономия времени программиста может быть достигнута на следующих этапах создания программ:
разработка алгоритма функционирования;
отладка;
поддержка - модификация и исправление ошибок.

 

Сразу отметим, что уменьшение временных затрат на всех этапах зависит не только от степени знания программистом того или иного языка. Не менее, а зачастую и более, значимыми здесь являются общая эрудиция и собдюдение технологии программирования. Любая технология в конечном счете есть набор правил и процедур их применения, нацеленных на эффективное создание конечного продукта. Остановимся на части этих правил, касающихся создания процедур/функций.(2)

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

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

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

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

На этапе декомпозиции задачи на подзадачи следует придерживаться трех правил:

  1. каждая подзадача должна иметь один и тот же уровень рассмотрения;
  2. каждая подзадача может быть решена независимо;
  3. полученные решения могут быть объединены вместе, позволяя решить исходную задачу.

 

Абстракция как инструмент декомпозиции

 

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

Абстракция подразумевает собой процесс изменения уровня детализации программы. Когда мы абстрагируемся от проблемы, мы предполагаем игнорирование ряда подробностей с тем, чтобы свести задачу к более простой. После этого декомпозиция такой упрощенной задачи становится более простой

Таким образом если декомпозиция позволяет разделить задачи на подзадачи, то абстракция позволяет производить этот процесс обдуманно и обоснованно.

Уже упоминалось, что процесс абстракции подразумевает собой некоторое обобщение (отвлечение от деталей; собственно само слово абстракция переводится именно так - отвлечение). Этот процесс знаком каждому из нас с детства. Когда-то мы научились объединять свою куклу со всеми остальными - дошли до абстракции игрушка; в первом классе от конкретной задачи "3 яблока + 2 груши = ? фруктов" перешли к осознанию более абстрактного выражения "3+2 = ?", а затем и вовсе "X+Y = ?". Абстрактное мышление делает из просто человека человека творящего, а Программисты по определению - люди творческие.

Рассмотрим виды абстракций, могущие оказаться нам полезными.

Абстракция через параметризацию

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

Например у нас существует процедура сортировки массива:

Procedure Sort(Var A: TArray; N: Word);

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

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

Абстракция через спецификацию

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

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

На примере той же процедуры сортировки: если спецификация написана следующим образом

{Сортирует первые N элементов массива A по возрастанию. Предполагается, что массив индексируется с 0 (последний отсортированный элемент - N-1)}

тогда процедура обязана производить сортировку и выдавать должный результат. При этом она не должна изменять элементы массива с индексами, большими N-1: этого нет в спецификации. С другой стороны пользователь не должен предполагать, что процедура будет производить сортировку быстро - по той же причине. В обоих случаях пользователь процедуры освобождается от необходимости знать хоть один алгоритм сортировки (хотя это и странно для программиста).

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

Процедурная абстракция

Процедурная абстракция или процедура - наиболее известный в программировании тип абстракции. Всякий, кто применял для выполнения функции подпрограмму, реализовывал тем самым процедурную абстракцию в применении к алгоритмам. Процедуры объединяют в себе методы абстракции через параметризацию и спецификацию, позволяя абстрагировать отдельную операцию или событие.

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

Применение процедурной абстракции наделяет проводимую на ее базе декомпозицию следующими качествами:
локальность;
модифицируемость;
многократность использования кода.

 

Локальность подразумевает, что реализация одной абстакции может быть проиведена без анализа реализации какой-либо другой абстракции (читай: процедуры, библиотеки или модуля).

Модифицируемость означает,что изменение реализации одной абстракции без изменения спецификации не приводит к изменению реализации любой другой абстракции.

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

Заключение

 

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

 

(1) (Обратно) Стоит отметить, что целесообразность написания критичных ко времени выполнения программ на Pascal'е и вообще на ЯП высокого уровня крайне сомнительна: ни один компилятор не создаст максимально оптимизированного кода. Исключение составляют задачи, несколько копий которых должны одновременно выполняться в мультизадачной системе.

(2) (Обратно) Стоит отметить, что приводимые правила не являются единственными как в том смысле, что технология состоит не только из них, так и в том, что возможно существование другого набора правил, направленных на те же цели.

(3) (Обратно) Большими принято называть программы, размер которых превосходит несколько десятков тысяч строк. Практика показывает, что любым, даже самым плохим образом, спроектированная программа, размер которой не превосходит двух тысяч строк, может быть приведена в работоспособное состояние методом грубой силы - отладкой глюка за глюком.

 

На первую страницу

Rambler's Top100 Rambler's Top100
PROext: Top 1000

(с)Все права защищены

По всем интересующим вопросам прошу писать на электронный адрес

Hosted by uCoz