Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
книги хакеры / Питер_Гудлиф_Ремесло_программиста_Практика_написания_хорошего_кода.pdf
Скачиваний:
16
Добавлен:
19.04.2024
Размер:
9.23 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

274m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Глава 11. Жажда скоростиClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

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

Программирование цифровой обработки сигналов (DSP) в высшей степени зависит от высокой производительности. Цифровые про% цессоры сигналов – это специальные устройства, оптимизирован% ные для быстрой цифровой фильтрации больших объемов данных. Без высокой скорости они были бы никому не нужны. Программи% рование DSP обычно в меньшей мере полагается на оптимизирую% щие свойства компилятора, поскольку здесь требуется высокая сте% пень контроля над работой процессора в каждый момент времени. Программисты DSP достигли большого мастерства в получении максимальной производительности от этих устройств.

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

Системы реального времени требуют своевременного выполнения

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

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

ипараллельных вычислений.

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

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

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

Технические подробности

Каким же образом выполнять оптимизацию? Гораздо важнее уяснить правильный подход к оптимизации, чем выучить список конкретных

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Техническиеm

подробности

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

275Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

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

Вот шесть этапов для повышения скорости работы вашей программы:

1.Убедитесь, что программа слишком медленно работает и требует оптимизации.

2.Определите, какая часть кода самая медленная, и нацельте на нее свои усилия.

3.Проверьте производительность кода, выбранного для оптимизации.

4.Оптимизируйте код.

5.Протестируйте оптимизированный код и убедитесь, что он сохра% нил работоспособность (очень существенно).

6.Проверьте, насколько выросла скорость, и решите, что делать дальше.

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

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

Чтобы выполнить оптимизацию корректно, вы должны позаботиться об отсутствии влияния внешних факторов на работу вашего кода. Если условия будут меняться, вы не сможете правильно сравнить характе% ристики своего кода. Здесь помогают два важных приема:

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

…и…

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

Промежуточные сборки могут работать совсем не так, как окончатель% ные, в силу наличия данных для трассировки, символов объектных файлов и т. д.

Рассмотрим каждый из этапов оптимизации более подробно.

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

X

 

 

 

 

 

-

 

 

 

 

 

d

 

F

 

 

 

 

 

 

t

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

276m

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

.

 

 

 

 

 

.c

 

 

p

 

 

 

 

g

 

 

 

 

df

 

 

n

e

 

 

 

 

-xcha

 

 

 

Убедитесь, что нужна оптимизация

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

Глава 11. Жажда скоростиClick

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Прежде всего нужно проверить, действительно ли требуется оптими% зация. Если производительность кода приемлема, нет смысла ковы% рять его. Как сказал Кнут (цитируя C.A.R. Hoare): «Следует забыть о недостаточной эффективности примерно в 97% случаев; необдуман% ная оптимизация – корень всех зол». Есть столько убедительных осно% ваний не делать оптимизацию, что самый быстрый и безопасный ме% тод оптимизации – убедиться, что она вам не требуется.

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

Определите самую медленную часть кода

В этом месте большинство программистов совершает ошибку. Если вы собираетесь заниматься оптимизацией, нужно определить те точки, в которых она имеет смысл. Согласно некоторым исследованиям, в сред% нем 80% времени программы проводят в 20% своего кода (Boehm 87). Данное правило известно как правило 80/20.1 Это относительно не% большая часть кода, и она может оказаться незатронутой вашей опти% мизацией, в результате чего все ваши усилия окажутся малоэффек% тивными, поскольку оптимизированным окажется код, который ред% ко выполняется.

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

Как же определить, на что следует обратить внимание? Наиболее эф% фективно воспользоваться профайлером. Такая программа проводит хронометраж работы различных участков вашей программы. Она по% кажет вам, куда уходит 80% времени работы программы, поэтому вы узнаете, куда направить свои силы.

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

1Некоторые идут еще дальше, считая, что правило должно гласить «90/10».

2Код всегда выполняется с фиксированной скоростью, зависящей от такто% вой частоты ЦП, количества прочих процессов, которыми манипулирует

ОС, и приоритетом процесса.

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

Техническиеm

подробности

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

277Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

.c

 

 

.

 

 

 

 

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

Существует масса превосходных программ для измерения эффектив% ности – коммерческих и бесплатно распространяемых. Затраты на по% купку хорошего профайлера оправдывают себя: оптимизация может отнять у вас много времени. Но это и дорогой продукт. Если профайлер окажется для вас недоступен, есть ряд других технологий хронометра% жа, которыми можно воспользоваться.

Разместите сами в своем коде контроль времени исполнения. Про% верьте, чтобы источник временных отсчетов был точен и чтобы за% траты на чтение времени не слишком влияли на производитель% ность программы.

Подсчитайте число вызовов каждой функции (некоторые библиоте% ки для отладки обеспечивают поддержку такого рода действий).

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

Воспользуйтесь счетчиком команд; периодически прерывайте про% грамму в отладчике, чтобы выяснить, где находится управление. Это труднее осуществить в многопоточных программах, и такой способ очень медленный. Если у вас есть доступ к среде выполнения, можно написать вспомогательные программы для автоматизации такого тестирования – фактически собственный вариант профайлера.

Проверьте, как влияет отдельная функция на скорость выполнения программы, заставив ее выполняться медленнее. Если подозрения в причинах замедленности падают на определенную функцию, по% пробуйте вызвать ее два раза подряд вместо одного и посмотрите, как это влияет на время выполнения.1 Если программа станет вы% полняться на 10% дольше, то функция занимает примерно 10% времени работы. Это может быть самым примитивным способом хронометража.

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

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

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

чем количественную.