Микроэффективность

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

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

Центральная идея повышения производительности: сначала измере­ние и затем оптимизация макроэффективности. Можно значительно улуч­шить производительность, не занимаясь микроэффективностью.

Игнорируйте все предложения по повышению эффективности, пока программа не будет правильной. Худшее, что может быть сделано, – это начать беспокоиться о скорости программы до того, как она станет рабо­тать правильно. Быстрая, но неправильная программа бесполезна; медлен­ная, но правильная всегда имеет некоторую ценность, а может оказаться и вполне удовлетворительной

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

Не жертвуйте легкостью чтения ради эффективности. Как пра­вило, предложения по улучшению микроэффективности сводятся к сово­купности трюков и мешают достичь легкости восприятия.

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

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

Добивайтесь эффективности на основе измерений, а не догадок. Доказано, что программисты крайне слабо угадывают причины неудовле­творительной эффективности программ. Это не результат каких-то недос­татков самих программистов; из-за сложной природы программ и систем интуиция в вопросе об «узких» местах подводит почти всегда. Лучше всего при первоначальной разработке программы игнорировать большин­ство соображений, касающихся эффективности. Когда программа работает (и только в том случае, если ее эффективность неудовлетворительна), про­граммист должен выполнить измерения, чтобы обнаружить и исправить те самые знаменитые «5 % программы, занимающие 90 % времени». Если про­грамма была спроектирована правильно (это значит, что она легко адапти­руема), такие изменения post factum должны быть несложными.

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