Книга: Основы объектно-ориентированного программирования
Динамическое связывание и эффективность
Динамическое связывание и эффективность
Можно подумать, что сила механизма динамического связывания приведет во время выполнения к недопустимым накладным расходам. Такая опасность существует, но аккуратное проектирование языка и хорошие методы его реализации могут ее предотвратить.
Дело в том, что динамическое связывание требует несколько большего объема действий во время выполнения. Сравним вызов обычной процедуры в традиционном языке программирования (Pascal, Ada, C, ...)
1
f (x, a, b, c...)
с ОО-формой
3.
x.f (a, b, c...)
Разница между этими двумя формами уже была разъяснена при введении понятия класса, для идентификации типа модуля. Но сейчас мы понимаем, что это связано не только со стилем, имеется также различие и в семантике. В форме (1), какой именно компонент обозначает имя f известно статически во время компиляции или, в худшем случае, во время компоновки, если для объединения раздельно откомпилированных модулей используется компоновщик. Однако при динамическом связывании такая информация недоступна статически: для f в форме (2) выбор компонента зависит от объекта, к которому присоединен x во время конкретного выполнения. Каким будет этот тип нельзя (в общем случае) определить по тексту программы, это служит источником гибкости этого ранее разрекламированного механизма.
Предположим вначале, что динамическое связывание реализовано наивно. Во время выполнения хранится копия иерархии классов. Каждый объект содержит информацию о своем типе - вершине в этой иерархии. Чтобы интерпретировать во время выполнения x.f, окружение ищет соответствующую вершину и проверяет, содержит ли этот класс компонент f. Если да, то прекрасно, мы нашли то, что требовалось. Если нет, то переходим к вершине-родителю и повторяем всю операцию. Может потребоваться проделать путь до самого верхнего класса (или нескольких таких классов в случае множественного наследования).
В типизированном языке нахождение подходящего компонента гарантировано, но в нетипизированном языке, таком как Smalltalk, поиск может быть неудачным, и придется завершить выполнение диагнозом "сообщение не понято". |
Такая схема все еще применяется с различными оптимизациями во многих реализациях не статически типизированных языков. Она приводит к существенным затратам, снижающим эффективность. Хуже того, эти затраты не прогнозируемы и растут с увеличением глубины структуры наследования, так как алгоритм может постоянно проходить путь до корня иерархии наследования. Это приводит к конфликту между повторным использованием и эффективностью, поскольку упорная работа над повторным использованием м приводит к введению дополнительных уровней наследования. Представьте состояние бедного разработчика, который перед добавлением нового уровня наследования должен оценить, как это ударит по эффективности. Нельзя ставить разработчиков ПО перед таким выбором.
Такой подход является одним из главных источников неэффективности реализаций языка Smalltalk. Это также объясняет, почему он (по крайней мере, в коммерческих реализациях) не поддерживает множественного наследования. Причина - в том, что из-за необходимости обходить весь граф, а не одну ветвь, накладные расходы оказываются чрезмерными.
К счастью, использование статической типизации устраняет эти неприятности. При правильно построенной системе типов и алгоритмах компиляции нет никакой нужды перемещаться по структуре наследования во время выполнения. Для ОО-языка со статической типизацией возможные типы x не произвольны, а ограничены потомками исходного типа x, поэтому компилятор может упростить работу системы выполнения, построив массив структурных данных, содержащих всю необходимую информацию. При наличии этих структур данных накладные расходы на динамическое связывание сильно уменьшаются: они сводятся к вычислению индекса и доступу к массиву. Важно не только то, что такие затраты невелики, но и то, что они ограничены константой, и поэтому можно не беспокоиться о рассмотренной выше проблеме соотношения между переиспользуемостью и эффективностью. Будет ли структура наследования в вашей системе иметь глубину 2 или 20, будет ли в ней 100 классов или 10000, максимальные накладные расходы всегда одни и те же. Они не зависят и от того, является ли наследование единичным или множественным.
- Динамическое распределение памяти
- 9.5. Эффективность
- Эффективность кампании. Показатель № 5 – коэффициент отклика
- Глава 4 Как повысить эффективность публичного выступления без бюджета
- Метод визуализации и эффективность работы команды
- 3.4. Как оценить эффективность затрат при проведении мероприятий?
- Динамическое распределение IP-адресов
- Учет и контроль в маркетинге: как определить критерий успеха, установить KPI, измерить и оценить эффективность промоакци...
- Связывание (binding)
- Связывание с нужным объектом каталога
- Элемент D6 Искусство или эффективность
- 7.12. Динамическое назначение методов