Шрифт:
Интервал:
Закладка:
Программы — это, если уж на то пошло, просто длинные списки инструкций для компьютера, и, хотя компьютеры работают очень быстро, их возможности не безграничны. Чтобы сделать быстрое программное обеспечение, инструкции в программе должны быть настолько эффективны, насколько это возможно, но не всегда очевидно, какую из них можно будет выполнить быстрее.
Приведем пример. Если я приглашу вас к себе на кухню и попрошу:
• Вытащить баночку горчицы из холодильника.
Вы легко справитесь с этим заданием, поскольку на моей кухне специй и приправ довольно много. Также понятно, что на выполнение этой инструкции уйдет меньше времени, чем потребуется для того, чтобы сделать указанное в инструкции той же длины:
• Пойти в супермаркет и купить баночку горчицы.
Поскольку в одних инструкциях заключается более высокий уровень понятийной сложности, чем в других, на их выполнение может потребоваться больше — иногда даже намного больше — времени. Если я останусь у себя на кухне во время теста с баночкой горчицы, я успею вытащить ее из холодильника несколько десятков раз, пока вы будете ходить в магазин. Но, опять же, многое зависит от того, далеко ли находится супермаркет. Для понимания сущности оптимизации ключевое слово в предыдущем предложении — это «зависит». Тщательно разработанное программное обеспечение основывается на искусной взаимосвязанной сети зависимостей между отдельными компонентами, и работа с этими взаимоотношениями — неотъемлемая часть создания сложного ПО, такого, как браузер. Пример с банкой горчицы иллюстрирует, насколько принципиальна эта проблема, и показывает, как широко она распространена и как трудно программисту с первого взгляда понять, с какой скоростью может работать определенный кусок кода, даже если суть инструкции полностью ясна.
Как это связано с оптимизацией? Вот ряд инструкций для следующего кухонного задания:
• Вытащить все из моего холодильника.
• Расставить предметы на стойке.
А вот попытка оптимизации:
• Вытащить все из моего холодильника.
• Расставить предметы на стойке.
• Сделать как можно меньше подходов.
Эта третья инструкция вносит поправку о скорости выполнения задания. Количество ходок между холодильником и стойкой ложится в основу проблемы, и подразумевается, что если его получится уменьшить, то вся операция в целом может быть выполнена быстрее.
Верно ли это? Эта попытка оптимизации поднимает несколько вопросов. Если переносить продукты большими охапками, это может быть быстрее… но действительно ли это так? Если я пытаюсь сгрести и подхватить большое количество банок с горчицей и майонезом, пакетов с молоком, пачек масла и пластиковый контейнер с остатками жареной свинины со вчерашнего вечера, то могу уронить что-нибудь, пытаясь перенести все за один раз. Это ошибка, верно? Если я пролью или разобью что-либо, не придется ли мне тратить время на то, чтобы все отмыть и отчистить, прежде чем задание можно будет считать выполненным? Если я вернусь к инструкции «Сделать как можно меньше подходов», чтобы поразмыслить о том, что же это все-таки значит, я приду к выводу, что моя цель — все-таки уменьшить количество походов между холодильником и стойкой, но верно ли я думаю? Не знаю. Это просто моя лучшая догадка. У меня нет достаточного понимания ситуации в целом, чтобы быть полностью уверенным в конечной цели задания.
Этот один из возможных вариантов развития событий показывает нам, почему такой опытный программист, как Кнут, считает нужным предостеречь на счет оптимизации. Эта дополнительная инструкция «Сделать как можно меньше подходов» повышает шанс ошибок, добавляет двусмысленность, из-за которой труднее изменить код, ведь на самом деле мы не знаем главной причины, по которой был добавлен этап, и конечный результат, вероятно, не окажется быстрее. Эта добавленная для «оптимизации» инструкция может создать больше проблем, чем выгоды. Кнут предполагает, что в 97 процентах случаев так оно и есть.
Теперь становится полностью понятно, почему PLT была таким важным тестом. Программа помогала увидеть, как наши инструкции влияют на главную задачу — добиться скорости, — и точно показывала нам, где и когда мы замедлили наш исходный код. PLT говорила нам, где стоит обратить внимание на то, что Кнут называл «низкой эффективностью». Это был наш главный инструмент для поиска 3 процентов, способ точно узнать, что оптимизация была не «преждевременной». Мы были уверены, что каждая оптимизация, которую мы делаем, помогает двигать производительность в нужном направлении.
В программировании существует традиционная точка зрения, что «преждевременность», о которой говорит Кнут, каким-то образом связана с расписанием проекта.
Как правило, программисты сначала делают так, чтобы код работал корректно, а к ускорению переходят, когда бо́льшая часть его ошибок исправлена. Это обычное дело — сначала отладить работу всех функций и только потом заниматься оптимизацией производительности.
Тем не менее, когда на доведение функций до ума уходит больше времени, чем ожидалось, а график выпуска продукта нельзя изменить, у руководства просто может не быть другого выбора, кроме как полностью отказаться от работ по повышению производительности.
Поскольку мы получили указание увеличить производительность от самого Стива, мы не могли допустить, чтобы подобное произошло, и Дон придумал, как это сделать. Он хотел, чтобы мы тщательно выбирали возможности для оптимизации, чтобы мы очень четко улавливали, понимали, знали, какие именно вещи замедляют процесс, и убирали их в тот самый момент, когда обнаружили снижение скорости. PLT помогала нам верно распределять оптимизацию во время всей нашей работы. Мы оптимизировали, когда четко знали, что делаем, это была непосредственная реакция на измерение кода тестовой программой.
Тем не менее даже с PLT оптимизация оставалась непростым делом, и иногда в поисках способов улучшить производительность приходилось подробно разбираться, почему код работает именно так и как он мог бы работать иначе. Например, оптимизация задания по опустошению холодильника на кухне могла бы потребовать всестороннего исследования, чтобы определить, максимум сколько предметов человек может перенести за один раз с наименьшим шансом что-либо уронить. Наверняка стоило бы подумать, как человеку еще и «выгрузить» из рук и расставить на стойке. Поиски самого быстрого метода могут привести вот к такой косвенной мысли: если уменьшение количества ходок между холодильником и стойкой действительно является приоритетным, то, возможно, стоит потратить время и принести из кладовки или гаража коробку и сразу переместить все предметы, находящиеся в холодильнике, а не бегать с ними несколько раз.
Иногда