Оптимизация программ

31 июля 2011

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

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

Рассмотрим законы оптимизации, которые работают не только в программировании, но и в реальной жизни.

Закон № 1

Оптимизировать можно все. Даже там, где вам кажется, что все и так работает быстро, можно сделать еще быстрее.

Это действительно так. И этот закон очень сильно проявляется в программировании. Идеального кода не существует. Даже простую операцию сложения 2 + 2 тоже можно оптимизировать. Чтобы достичь максимального результата, нужно действовать последовательно и, желательно, в том порядке, в котором описано далее.

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

Закон № 2

Первое, с чего нужно начинать, — это поиск самых слабых и медленных мест.

Зачем начинать оптимизацию с того, что и так работает достаточно быстро! Если вы будете оптимизировать сильные места, то можете встретить неожиданные конфликты. Да и эффект будет минимален. Если вы ускорите работу самого слабого звена Вашей программы то, может быть, и не понадобится ускорять другие места. Вы можете потратить дни и месяцы на оптимизацию сильных сторон и увеличить производительность только на 10% (что может оказаться недостаточным) или несколько часов на совершенствование слабой части и получить улучшение в 10 раз!

Слабые места компьютера

Не надо гнаться за мегагерцами процессора, когда у Вас доисторическая видеокарта S3 и оперативной памяти 32 Мбайт. В таком случае наращивание сотни мегагерц у процессора даст меньший прирост в скорости. Если вы используете "тяжелые" приложения при нехватке памяти, то процессор начинает тратить слишком много времени на загрузку и выгрузку данных в файл подкачки. Ну а если в вашем компьютере достаточно оперативной памяти, то процессор уже занимается только расчетами и не расходует драгоценное время на лишние загрузки/вы грузки.

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

Поиск слабых мест

Как правильно определить слабое место программы? Что, если вы неправильно определите слабое место и зря потратите время? Все очень просто, ибо можно воспользоваться специализированными утилитами, которые помогут найти функции, на выполнение которых процессор тратит больше всего времени. Наиболее популярной является разработка компании Intel — VTune Performance Analyzer.

Эта программа анализирует выполнение кода и определяет наиболее медленно выполняемые участки, отображая их графически. Именно на них нужно обратить внимание. Сократив их всего на несколько тактов, можно выиграть драгоценные секунды в выполнении.

Закон № 3

Начинать оптимизацию нужно циклических повторений программы.

Допустим, что, у вас есть следующая логика выполнения:

1. А = А*2;

2. B = 1;

3. X = X+B;

4. B = B+1;

5. Если B < 200, то перейти п.3

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

Еще в этом коде используется цикл: Если B < 200, то будет выполняться операция Х=Х+B. Это значит, что процессору придется выполнить 200 переходов с шага 5 на шаг 3. А это уже немало. Что здесь можно оптимизировать? В цикле выполняются две строки: 3 и 4, возьмем и внутри цикла размножим их 2 раза:

1. А = А*2;

2. B = 1;

3. X = X+B;

4. B = B+1;

5. X = X+B;

6. B = B+1;

7. Если B < 100, то перейти п.3

Здесь изменился цикл. Вторую и третью операции мы повторили два раза. Это значит, что за один проход нового цикла выполняются два раза строки 3 и 4, и только после этого произойдет переход на строку 3 для повторения операции. Такой цикл уже нужно повторить только 100 раз. Таким образом, экономия 100 операций переходов. Если строки в цикле написать строки 2 и 3 десять раз. Это значит, что понадобиться 20 операций переходов, а экономия составит 180 операций переходов.

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

Закон № 4

Оптимизировать одноразовые операции — это только потеря времени.

Закон № 5

Нужно знать "внутренности" компьютера и принципы его работы. Чем лучше вы знаете, каким образом компьютер будет выполнять ваш код, тем лучше вы сможете его оптимизировать. Вот основные подходы, связанные с особенностями выполнения кода:

Старайтесь поменьше использовать вычисления с плавающей запятой. Любые операции с целыми числами выполняются в несколько раз быстрее.

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

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

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

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

Не используйте длинных указателей. Допустим, что у вас есть следующий КОД: ClassName->SubClass->SubSubClass-> Property. Если в функции происходит несколько обращений к такому свойству, то это будет неэффективно. Каждый раз необходимо будет развертывать эту длинную цепочку для получения адреса переменной. Намного эффективнее будет завести локальную переменную в начале функции, присвоить ей значение и использовать локальную переменную.

Закон № 6

Для сложных расчетов можно подготовить таблицы с заранее определенными результатами и потом использовать эти таблицы в режиме реального времени. На пример, такие легендарные игры как Doom и Quake использовали заранее просчитанные графические сцены.

Закон № 7

Лишних проверок не бывает.

Чаще всего оптимизация приводит к нестабильности исполняемого кода, потому что для увеличения быстродействия многие убирают «не нужные» проверки. Лишних проверок не бывает! Если вы думаете, что какая-то нестандартная ситуация может не возникнуть, то она не возникнет только у вас. У пользователя, который будет эксплуатировать вашу программу, может возникнуть все что угодно. Он непременно нажмет на то, на что не нужно, или введет неправильные данные.

Обязательно делайте проверки всего того: что вводит пользователь. Делайте это сразу же, и не ждите, когда введенные данные понадобятся. По возможности не выполняйте проверки в цикле, а выносите все за его пределы. Любые лишние операторы if внутри цикла очень сильно влияют на производительность.

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

Закон № 8

Не переусердствуйте с оптимизацией. Слишком большие затраты ив ускоре­ние выполнения кода могут свести на нет приложенные усилия. Ставьте перед собой реальные цели и задачи.

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

Рейтинг@Mail.ru