Статическое связывание как оптимизация
Статическое связывание как оптимизация
В некоторых случаях главным требованием является эффективность, и даже указанные выше небольшие накладные расходы нежелательны. В этом случае можно заметить, что они не всегда обоснованы. Вызов x.f (a, b, c...) не нуждается в динамическом связывании в следующих случаях:
1 f нигде в системе не переопределяется (имеет только одно объявление);
2 x не является полиморфной, иначе говоря, не является целью никакого присоединения, источник которого имеет другой тип.
В любом из таких случаев, выявляемых хорошим компилятором, сгенерированный для x.f (a, b, c...) код может быть таким же, как и код, генерируемый компиляторами C, Pascal, Ada или Fortran для вызова f (x, a, b, c...). Никакие накладные расходы не потребуются.
Компилятор ISE, являющийся частью окружения, описанного в последней лекции, сейчас выполняет оптимизацию (1), планируется добавить и (2) (анализ (2) является, фактически, следствием механизмов анализа типов, описанных в лекции о типизации).
Хотя (1) интересно и само по себе, непосредственная его польза ограничивается сравнительно низкой стоимостью динамического связывания (см. приведенную выше статистику). Настоящий выигрыш от него непрямой, поскольку (1) дает возможность третьей оптимизации:
4. При любой возможности применять автоматическую подстановку кода процедуры.
Такая подстановка означает расширение тела программы текстом вызываемой процедуры в месте ее вызова. Например, для процедуры
set_a (x: SOME_TYPE) is
-- Сделать x новым значением атрибута a.
do
a := x
end
компилятор может сгенерировать для вызова s.set_a (some_value) такой же код, какой компилятор Pascal сгенерирует для присваивания s.a := some_value (недопустимое для нас обозначение, поскольку оно нарушает скрытие информации). В этом случае вообще нет накладных расходов, поскольку сгенерированный код не содержит вызова процедуры.
Подстановка кода традиционно рассматривается как оптимизация, которую должны задавать программисты. Ada включает прагму (указание транслятору) inline, C и С++ предлагают аналогичные механизмы. Но этому подходу присущи внутренние ограничения. Хотя для небольшой, статичной программы компетентный программист может сам определить, какие процедуры можно подставлять, для больших развивающихся проектов это сделать невозможно. В этом случае компилятор с приличным алгоритмом определения подстановок будет намного превосходить догадки программистов.
Для каждого вызова, к которому применимо автоматическое статическое связывание (1), ОО-компилятор может определить, основываясь на анализе соотношения между временем и памятью, стоит ли применять автоматическую подстановку кода процедуры (3). Это одна из самых поразительных оптимизаций - одна из причин, по которой можно достичь эффективности произведенного вручную кода Си или Фортрана, а иногда, на больших системах и превзойти ее.
К улучшению эффективности, растущему с увеличением размера и сложности программ, автоматическая подстановка кода добавляет преимущество большей надежности и гибкости. Как уже отмечалось, подстановка кода семантически корректна только для процедуры, которую можно статически ограничить, например, как в случаях (1) и (2). Это не только допустимо, но также вполне согласуется с ОО-методом, в частности, с принципом Открыт-Закрыт, если разработчик на полпути разработки большой системы добавит переопределение некоторого компонента, имевшего к этому моменту только одну реализацию. Если же код процедуры вставляется вручную, то в результате может получиться программа с ошибочной семантикой (поскольку в данном случае требуется динамическое связывание, а вставка кода, конечно, означает статическое связывание). Разработчики должны сосредотачиваться на построении корректных программ, не занимаясь утомительными оптимизациями, которые при выполнении вручную приводят к ошибкам, а на деле могут быть автоматизированы.
Имеются и некоторые другие требования для того, чтобы подстановка кода была корректной, в частности, она применима только к нерекурсивным вызовам. Даже корректную подстановку следует применять при разумном соотношении между временем и памятью: подставляемая процедура должна быть небольшой и должна вызываться небольшое число раз.Последнее замечание об эффективности. Опубликованная статистика для ОО-языков показывает, что где-то от 30% до 60% вызовов на самом деле используют динамическое связывание. Это зависит от того, насколько интенсивно разработчики используют специфические свойства методов. В системе ISE это соотношение близко к 60%. С использованием только что описанных оптимизаций платить придется только за динамическое связывание только тех вызовов, которые действительно в нем нуждаются. Для оставшихся динамических вызовов накладные расходы не только малы (ограничены константой), но и логически необходимы, - в большинстве случаев для достижения результата, эквивалентного динамическому связыванию, придется использовать условные операторы (if ... then ... или case ... of ...), которые могут оказаться дороже приведенного выше простого механизма, основанного на доступе к массивам. Поэтому неудивительно, что ОО-программы, откомпилированные хорошим компилятором, могут соревноваться с написанным вручную кодом на C.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
Неявное связывание
Неявное связывание Неявное связывание, или связывание во время загрузки (load-time linking) является простейшей из двух методик связывания. Порядок действий в случае использования Microsoft C++ следующий:1. После того как собраны все необходимые для новой DLL функции, осуществляется
Явное связывание
Явное связывание Явное связывание, или связывание во время выполнения (run-time linking), требует, чтобы в программе содержались конкретные указания относительно того, когда именно необходимо загрузить или освободить библиотеку DLL. Далее программа получает адрес запрошенной
Статическое выделение памяти в стеке
Статическое выделение памяти в стеке В пространстве пользователя многие операции выделения памяти, в частности некоторые рассмотренные ранее примеры, могут быть выполнены с использованием стека, потому что априори известен размер выделяемой области памяти. В
Статическое архивирование в действии
Статическое архивирование в действии Есть способ обойтись просто парой строчек в конфигурационном файле (httpd.conf или .htaccess, первое предпочтительнее), если потратить пару минут и самостоятельно заархивировать все необходимые файлы. Предположим, что у нас есть
Связывание (binding)
Связывание (binding) Прежде чем клиент сможет вызвать удаленную процедуру, необходимо связать его с удаленной системой, располагающей требуемым сервером. Таким образом, задача связывания распадается на две:? Нахождение удаленного хоста с требуемым сервером? Нахождение
11.9.3 Связывание
11.9.3 Связывание Сервер DHCP хранит таблицу соответствия между клиентами и их конфигурационными параметрами. Связывание заключается в назначении каждому клиенту IP-адреса и набора конфигурационных
R.3.3 Программа и связывание
R.3.3 Программа и связывание Программа состоит из одного или нескольких файлов, связываемых вместе (§R.2). Файл состоит из последовательности описаний. Имя с файловой областью видимости, которое явно описано как static, является локальным в своей единице трансляции и может
Статическое состояние
Статическое состояние Ключевое слово Static в объявлении переменной следует использовать тогда, когда вы хотите, чтобы переменная оставалась в памяти, - для того чтобы использовать ее значение - даже когда процедура завершила свою работу. В следующем примере переменная
Динамическое связывание
Динамическое связывание Упрощенно говоря, динамическое связывание, или динамическая привязка, - это подход, с помощью которого можно создавать экземпляры заданного типа и вызывать их члены в среде выполнения и условиях, когда во время компиляции о типе еще ничего не
9.1.7. Безопасное связывание A
9.1.7. Безопасное связывание A При использовании перегрузки складывается впечатление, что в программе можно иметь несколько одноименных функций с разными списками параметров. Однако это лексическое удобство существует только на уровне исходного текста. В большинстве
Связывание видов
Связывание видов Среди инструментов визуализации ArchiCAD существует механизм, назначение которого – одновременное совместное отображение двух различных видов. Какой в этом смысл?Необходимость в этом возникает довольно часто. Например, для визуальной привязки объектов
Динамическое связывание
Динамическое связывание Сочетание последних двух механизмов, переопределения и полиморфизма, непосредственно предполагает следующий механизм. Допустим, есть вызов, целью которого является полиморфная сущность, например сущность типа BOAT вызывает компонент turn.
Связывание с АТД
Связывание с АТД Класс, как неоднократно говорилось, является реализацией АТД, заданного формальной спецификацией или неявно подразумеваемого. В начале лекции отмечалось, что утверждения можно рассматривать, как способ введения в класс семантических свойств, лежащих в
Динамическое связывание
Динамическое связывание Динамическое связывание дополнит переопределение, полиморфизм и статическую типизацию, создавая базисную тетралогию
Кнопка под другим именем: когда статическое связывание ошибочно
Кнопка под другим именем: когда статическое связывание ошибочно К этому моменту должен стать понятным главный вывод из изложенных в этой лекции принципов наследования:Принцип динамического связыванияЕсли результат статического связывания не совпадает с результатом
Типизация и связывание
Типизация и связывание Хотя как читатель этой книги вы наверняка отличите статическую типизацию от статического связывания, есть люди, которым подобное не под силу. Отчасти это может быть связано с влиянием языка Smalltalk, отстаивающего динамический подход к обеим задачам