Главная - Литература

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 [191] 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294

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

Увы, эффективный код не всегда является «лучшим». Этот вопрос мы и обсудим ниже.

Принцип Парето

Принцип Парето, известный также как «правило 80/20», гласит, что 80% результата можно получить, приложив 20% усилий. Относящийся не только к программированию, этот принцип очень точно характеризует оптимизацию программ.

Барри Бом сообщает, что на 20% методов программы приходятся 80% времени ее выполнения (Boehm, 1987b). В классической работе «Ап Empirical Study of Fortran Programs» Дональд Кнут указал, что менее 4% кода обычно соответствуют более чем 50% времени выполнения программы (Knuth, 1971).

Кнут обнаружил это неожиданное отношение при помощи инструмента профилирования, поддерживающего подсчет строк. Следствие очевидно: вам нужно найти в коде «горячие точки» и сосредоточиться на оптимизации процентов, используемых более всего. Профилируя свою программу подсчета строк, Кнут обнаружил, что половину времени она проводила в двух циклах. Он изменил несколько строк кода и удвоил скорость профайлера менее чем за час.

Джон Бентли описывает случай, когда программа из 1000 строк проводила 80% времени в 5-строчном методе вычисления квадратного корня. Утроив быстродействие этого метода, он удвоил быстродействие программы (Bentley, 1988). Опираясь на принцип Парето, можно дать еще один совет: напишите большую часть кода на интерпретируемом языке (скажем, на Python), а потом перепишите проблемные фрагменты на более быстром компилируемом языке, таком как С.

Бентли также сообщает о случае, когда группа обнаружила, что ОС половину времени проводит в одном небольшом цикле. Переписав цикл на микрокоде, разработчики ускорили его выполнение в 10 раз, но производительность системы осталась прежней - они переписали цикл бездействия системы!

Разработчики языка ALGOL - прародителя большинства современных языков, сыгравшего одну из самых главных ролей в истории программирования, - руководствовались принципом «Лучшее - враг хорошего». Стремление к совершенству может мешать завершению работы. Доведите работу до конца и только потом совершенствуйтесь. Часть, которую нужно довести до совершенства, обычно невелика.



Бабушкины сказки

с оптимизацией кода связано множество заблуждений.

Сокращение числа строк высокоуровневого кода повышает быстродействие или уменьшает объем итогового машинного кода - НЕВЕРНО!

Многие убеждены в том, что, если сократить какой-то фрагмент до одной или двух строк, он будет максимально эффективным. Рассмотрим код инициализации массива из 10 элементов:

for i = 1 to 10

а[ i ] = i end for

Как вы думаете, он выполнится быстрее или медленнее, чем эти 10 строк, решающих ту же задачу?

1 ] =

2 ] =

3 ] =

4 ] =

5 ] =

6 ] =

7 ] =

8 ] =

9 ] =

10 ] :

= 10

Если вы придерживаетесь старой догмы «меньшее число строк выполняется быстрее», вы скажете, что первый фрагмент быстрее. Однако тесты на Microsoft Visual Basic и Java показали, что второй фрагмент минимум на 60% быстрее первого.

Время

Время выполнения

выполнения

последовательного

Экономия

Соотношение

Язык

цикла for

кода

времени

быстродействия

Visual Basic

8,47

3,16

2,5:1

Java

12,6

3,23

Примечания: (1) Временные показатели в этой и следующих таблицах данной главы указываются в секундах, а их сравнение имеет смысл только в пределах конкретных строк каждой из таблиц. Действительные показатели будут зависеть от компилятора, параметров компилятора и среды, в которой выполняется тестирование. (2) Большинство результатов сравнительного тестирования основано на выполнении фрагментов кода от нескольких тысяч до многих миллионов раз, что призвано устранить колебания результатов. (3) Конкретные марки и версии компиляторов не указываются. Показатели производительности во многом зависят от марки и версии компилятора. (4) Сравнение результатов тестирования фрагментов, написанных на разных языках, имеет смысл не всегда, так как компиляторы разных языков не всегда позволяют задать одинаковые параметры генерирования кода. (5) Фрагменты, написанные на интерпретируемых языках (РНР и Python), в большинстве случаев тестировались с использованием более чем в 100 раз меньшего числа тестов, чем фрагменты, написанные на других языках. (6) Некоторые из показателей «экономии времени» не совсем точны из-за округления «времени выполнения кода до оптимизации» и «времени выполнения оптимизированного кода».



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

Одни операции, вероятно, выполняются быстрее или компактнее других - НЕВЕРНО! Если речь идет о производительности, не может быть никаких «вероятно». Без измерения производительности вы никак не сможете точно узнать, помогли ваши изменения программе или навредили. Правила игры изменяются при каждом изменении языка, компилятора, версии компилятора, библиотек, версий библиотек, процессора, объема памяти, цвета рубашки, которую вы надели (ладно, это шутка), и т. д. Результаты, полученные на одном компьютере с одним набором инструментов, вполне могуг оказаться противоположными на другом компьютере с другим набором инструментов.

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

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

Оптимизацию следует выполнять по мере написания

тл Возможности небольшдао новы-

кода - НЕВЕРНО! Кое-кто утверждает, что если вы буде- аффвкти81шш тЩ те стремиться написать самый быстрый и компактный код игнорировать, скажем, в 07% при работе над каждым методом, то итоговая программа бу- случаев: необдуманная ошми-дет быстрой и компактной. Однако на самом деле это ме- W» - корень всего зла. шает увидеть за деревьями лес, и программисты, чрезмер- Доишд Кнут (ОтШ KrnAh) но поглощенные микрооптимизацией, начинают упускать из виду по-настоящему важные глобальные виды оптимизации. Основные недостатки этого подхода рассмотрены ниже.

До создания полностью работоспособной программы найти узкие места в коде почти невозможно. Программисты очень плохо угадывают, на какие 4% кода приходятся 50% времени выполнения, поэтому, оптимизируя код по мере его написания, они будут тратить примерно 96% времени на оптимизацию кода, который не нуждается в оптимизации. На оптимизацию по-настоящему важных 4% кода времени у них уже не останется.

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



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 [191] 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294



0.008