Техника оптимизации программного кода. Вред и польза оптимизаций

Техника оптимизации программного кода. Вред и польза оптимизаций

Немного о грустном: вся наша жизнь – это борьба с тормозами. И вечно так продолжаться не может. Необходимо оптимизировать всё – начиная от своего рабочего места до времени. В этой статье я привёл примеры оптимизации кода на языке программирования Delphi, но поверь, эти советы могут пригодиться тебе и в реальной жизни, если подумать.

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

2. Оптимизацию всегда надо начинать со слабых мест в коде программы. Обычно оптимизировать то, что и так быстро работает, необходимости не возникает. Да и эффект такой оптимизации будет минимален.

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

4. Старайтесь поменьше использовать вычисления с плавающей запятой. Любые операции с целыми числами выполняются на порядок быстрее. Операции умножения или деления также выполняются достаточно долго. Вместо умножения лучше использовать сложение, а деление можно заменить сдвигом. Сдвиг работает намного быстрее и умножения, и деления. Это связано с тем, что все числа хранятся в двоичной системе. Если перевести число из десятичной системы счисления в двоичную и сдвинуть число вправо на одну позицию, то можно заметить, что данная операция аналогична делению на 2. При сдвиге влево происходит деление числа на 2. Хоть эти операции и аналогичны, но сдвиг работает в несколько раз быстрее.

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

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

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

8. Если ты пишешь достаточно большую и громоздкую программу, добавляй в неё комментарии. Компилятор их всё равно игнорирует. И если вдруг тебе захочется продать исходные коды своих программ, комментарии повысят им цену, да и самому будет легче в них ориентироваться.

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

10. Старайся делать в программах стандартный интерфейс. Ну не надо делать треугольные кнопочки, нестандартные меню и прочие графические навороты. Всё это очень сильно тормозит программу, расходует большое количество ресурсов компьютера и требует дополнительного времени на разработку. К примеру, настоящий UNIX – это вообще обычный shell – строка для ввода команд.

Вот вроде и всё. Желаю, удачи в написании своих программ, просто следуй этим советам, и всё у тебя получиться.

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

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

Оптимизации также могут классифицироваться в зависимости от области их применения на локальные (оператор, последовательность операторов, базовый блок), внутрипроцедурные, межпроцедурные, внутримодульные и глобальные (оптимизация всей программы, «оптимизация при сборке», «Link-time optimization»).

Отладка модуля с целью выявления логических ошибок

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

Отладка = Тестирование + Поиск ошибок + Редактирование.

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



Принципы и виды отладки программного средства

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

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

Модульное тестирование

Каждая сложная программная система состоит из отдельных частей – модулей, выполняющих ту или иную функцию в составе системы. Для того, чтобы удостовериться в корректной работе системы в целом, необходимо вначале протестировать каждый модуль системы в отдельности. В случае возникновения проблем это позволит проще выявить модули, вызвавшие проблему, и устранить соответствующие дефекты в них. Такое тестирование модулей по отдельности получило называние модульного тестирования (unit testing ).

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

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

При этом в ходе модульного тестирования решаются четыре основные задачи.

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

2. Поддержка разработки и рефакторинга низкоуровневой архитектуры системы и межмодульного взаимодействия – эта задача больше свойственна "легким" методологиям типа XP, где применяется принцип тестирования перед разработкой (Test-driven development), при котором основным источником требований для программного модуля является тест, написанный до самого модуля. Однако, даже при классической схеме тестирования модульные тесты могут выявить проблемы в дизайне системы и нелогичные или запутанные механизмы работы с модулем.

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

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

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

1. Не существует единых принципов определения того, что в точности является отдельным модулем.

2. Различия в трактовке самого понятия модульного тестирования – понимается ли под ним обособленное тестирование модуля, работа которого поддерживается только тестовым окружением, или речь идет о проверке корректности работы модуля в составе уже разработанной системы. В последнее время термин "модульное тестирование" чаще используется во втором смысле, хотя в этом случае речь скорее идет об интеграционном тестировании.

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

Оптимизация js и css

Для начала разберемся из css и js. Для чего нужна оптимизация css и js?

Около 50% пользователей уходят из сайта, если он грузится больше 3 секунд и при каждой дополнительной секунде конверсия сайта падает на 7%. Также скорость загрузки сайта является одним из факторов ранжирования.

Первое из чего нужно начать, это послушаться рекомендаций Google. Css и js код не должен содержаться в html коде сайта, его нужно вынести в отдельные файлы. Исключением являются небольшие инлайновые стили с 1-2 значениями. Число подключаемых файлов нужно максимально уменьшить, в идеальном случае оставив по одному подключаемому css и js файле. Подключение файлов js следует перенести в конец страницы (перед отображением страницы, браузер должен выполнить ее синтаксический анализ и если при этом он обнаруживает внешний скрипт, он должен его загрузить, а это лишний цикл операций, который замедляет показ страницы.

Также для ускорения загрузки js, css файлов и картинок желательно использовать кеширование и сжатие в формат GZIP.

SEO-верстка сайта: оптимизация html кода или как сверстать так, чтоб потом не переделывать

Для правильной будущей оптимизации html кода рассмотрим все теги и как они влияют на SEO.

Блок :

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

- позволяет задать описание страницы, которое появляется в поисковой выдаче под названием. Имеет значительно меньшее влияние на ранжирование, но помогает повысить CTR (отношение числа кликов кчислу показов) страницы. Если мета-тег description заполнен, это не гарантирует, что в выдаче будет показано именното, что там написано, так как поисковые системы могут взять описание из контента. Но все же лучше настроить генерацию тега и не думать, какую часть текста ПС возьмут для описания.

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

(берется одно из значений, index или noindex, follow или nofollow) — запрет на индексацию страницы (noindex) и запрет на индексацию исходящих ссылок на странице (nofollow) поисковыми системами. Значение index и follow используются вместе со значениями запрета индексации, так как по умолчанию индексация страниц и ссылок разрешена. Использовать данный тег следует осторожно, чтоб не увидеть через некоторое время нулевой трафик из поисковых систем.

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

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

Блок :

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

Теги - должны соблюдать логическую структуру. Заголовок содержать заголовки ,в которых заголовки и т.д. Использовать их желательно только в текстовом содержании страницы (например, для разбития основного контента на странице, но не для блоков, которые выводятся на всех страницах сайта). Если взять во внимание, что тег помогает повысить значение слов при ранжировании, заключить в него весь текстна сайте и поправить с помощью стилей, чтоб его можно было читать, то никакого преимущества это не даст, а только пойдет во вред такой странице.

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

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

.

Боковой блок с дополнительной информацией. ...

Что еще нужно учесть при SEO-верстке сайта
Заключение

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

Иногда бывает сложно решить, какую конструкцию лучше использовать i++ или ++i, либо выбрать между конструкцией if-else и switch. В этой статье, написанной специально для сообщества iT works, представлены наиболее реальные средства оптимизации кода, которые должен знать каждый профессиональный программист.

Некоторые считают, что времена оптимизации на уровне кода прошли навсегда, однако это не так. Сейчас существует множество платформ в которых нет таких могущественных компиляторов как в Microsoft Visual Studio. Например шейдерные языки (hlsl, glsl) или код для CUDA, PlayStation3, SPU или мобильные платформы. В зависимости от организации кода, может в десятки раз отличаться его эффективность иногда из-за неэффективности компилятора, на чаще из-за доступа к памяти.

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

Если вы являетесь программистом в VS под Windows, то скорее всего со многими описанными приемами оптимизации компилятор эффективно справится. Обратите внимание на пункты работы с памятью, а так же я рекомендую ознакомиться с техникой Data oriented design . Некоторые советы по ее использования ищите в статье .

Итак, начнем:

1. Используйте векторизацию данных и векторные команды их обработки (например SSE в CPU или упаковывайте данные если используете шейдеры или CUDA). Это позволит использовать SIMD (Single Instruction, Multiple Data) архитектуру, что значительно повысит скорость вычислений. Если вы решите использовать этот метод, то не забывайте про выравнивание данных в памяти.

2. Эффективнее складывать и умножать в перемешку, чем сначала все сложить, а потом все умножить. Это происходит от того, что сложение и умножение выполняются разными модулями процессора и могут выполняться одновременно.
int a,b,c,k,m,n,t,f1,f2,f3,g1,g2,g3; a = b + с; k = m + n; t = a + k; f1 = f2 * f3; g1 = g2 * g3; Менее эффективно чем: a = b + с; f1 = f2 * f3; k = m + n; g1 = g2 * g3; t = a + k;

3. Нет разницы по скорости в работе с float и double при сложении и умножении. Они выполняются за равное число тактов процессора и используют одни и те же регистры. При делении и извлечении корня, float работает быстрее. Однако если вы будете использовать большие объемы данных, то за счет кеша быстрее будет работать тот тип, который занимает меньше памяти (т.е. float), поэтому в общем случае именно его предпочтительно использовать. Выбирать double имеет смысл когда нужна большая точность.

4.
Допустим есть. const float a = 100.0f; float some1 = some3 * 1.0f / a; float some2 = some4 * 1.0f / a; более эффективно написать не: const float a_inv = 1.0f / a; some1 = some3 * a_inv; some2 = some4 * a_inv; а так: some1 = some3 * (1.0f / a); some2 = some4 * (1.0f / a); Почему это будет эффективнее? Операторы с равным приоритетом выполняются последовательно. Это значит, что будет выполнено сначала умножение, а затем деление. Если же обрамить операцию деления в скобки, то ее выполнит компилятор, а в реальном времени будет выполняться только операция умножения. Что качается отличий варианта 3 от варианта 2, то в 3-ем варианте не создается дополнительной переменной, нет нужны глядя на код думать о том, что это за переменная. А эффективность 2-го и 3-го варианты будет одинаковой.

5. На больших объемах данных и вычислений на них float выгоднее чем double (из за cache miss"ов, см. пункт 3).

6.
a, b - любое выражение Func1, Func2 - функции, которые вызовутся для вычисления условия if(a && b) - нужно первым ставить менее вероятное условие, для большей эффективности if(a || b) - нужно первым ставить более вероятное условие, для большей эффективности if(Func1() && Func2()) - нужно ставить более быстрый оператор первым

7.
void Func(int* a) { int b = 10; Следующие строки одинаковые по эффективности (по времени выполнения): b = 100; *a = 100; } Это происходит по тому, что доступ к стековой переменной осуществляется по указателю на стек. Тоже идет разыменование указателя.

8. Если есть большой массив структур, то нужно делать размер его элементов равным степени двойки. Тогда проход по такому массиву будет значительно быстрее (в 4 -6 раз), за счет выравнивания указателя на каждую структуру в массиве.

9.
int a[ 1000 ]; for(int i =0; i= b ? -1: 0); Можно заменить на: 1. int x = (b - a) >> 31; 2. int x = (b - a) & 0x80000000;

25.
i32 iIndex; Условие: if(iIndex < 0 && iIndex >= iSize) Можно заменить таким: if((u32)iIndex >= iSize) Условие: if(i >= min && i

просмотров