При разработке программного продукта особенно важно обеспечить достаточный уровень производительности. В данной статье рассматриваются критерии и методы улучшения производительности.
Ключевые слова: производительность, разработка, оптимизация, алгоритм.
Производительность
Производительность приложения является ключевым фактором его успеха. Пользователь ожидает от продукта отзывчивости и быстродействия. Несоответствие качества с ожидаемым приведет к оттоку пользователей. В то же время хорошая производительность позволит сэкономить ресурсы. Программный продукт будет потреблять меньше электроэнергии, будет требовать меньше вычислительных мощностей, а также будет проще масштабироваться, что позволит увеличить число пользователей и объем обрабатываемых данных. При работе с большими объемами данных, увеличении объема кода, вопрос быстродействия системы встает особенно остро.
Выбор языка
О производительности стоит начать задумываться уже на этапе выбора языка, поскольку выбор языка программирования может существенно влиять на скорость выполнения операций и общую производительность приложения. Так, например, одни из популярнейших языков программирования — Java и C++ известны, в том числе, своей высокой производительностью. Согласно результатам тестирования скорости работы языков программирования [1], Java показала гораздо лучшие результаты в решении задачи обучения нейронной сети. Тем не менее, не стоит забывать о сценарии использования приложения. Нейронная сеть — это лишь одна из множества задач, инструмент для выполнения которой должен быть подобран с умом. Так, например, java повсеместно используется при разработке мобильных приложений, а C++ регулярно применяется в игровой индустрии и при разработке операционных систем.
Выбор алгоритма
Чтобы добиться хорошей производительности, разработчик должен хорошо понимать код, анализировать его, дополнять и улучшать. Мало просто написать рабочий алгоритм: Одна и та же функция может быть написана несколькими способами. При этом, порой, приходится делать выбор между быстродействием и занимаемой памятью. В этом случае разработчик руководствуется временной и пространственной сложностью алгоритма. Временная сложность определяет время выполнения алгоритма и измеряется в количестве элементарных операций алгоритма при работе с данными, а пространственная сложность определяет объем занимаемой памяти. Также, у функций есть скорость роста.
«Мы описываем поведение алгоритма путем представления скорости роста времени выполнения в зависимости от размера входного экземпляра задачи. Такая характеристика производительности алгоритма является распространенной абстракцией, которая игнорирует многочисленные детали. Чтобы правильно использовать эту меру, требуется осведомленность о деталях, скрытых абстракцией. Каждая программа выполняется на определенной вычислительной платформе; под этим общим термином подразумевается масса конкретных деталей.
— Компьютер, на котором выполняется программа, его процессор (CPU), кеш данных, процессор для вычислений с плавающей точкой (FPU) и другие аппаратные возможности.
— Язык программирования, на котором написана программа, наряду с тем, является ли он компилируемым или интерпретируемым, и настройки оптимизации для генерации кода.
— Операционная система.
— Прочие процессы, выполняющиеся в фоновом режиме». [2]
К примеру, скорость роста времени алгоритма быстрой сортировки (quicksort) ниже, чем у сортировки вставками. Однако, сортировка вставками показывает себя лучше в случаях с маленькими размерами массивов.
Кроме роста функций, также сравниваются наилучший, средний и наихудший случаи использования алгоритма. Анализ данных параметров поможет выбрать наиболее подходящий алгоритм для решения задачи.
Оптимизация кода
Оптимизируя программу, стоит обратить внимание на следующее:
Циклы — наиболее ресурсоемкий участок кода. Минимизация числа итераций и вынесение лишних операций за рамки цикла позволят значительно сократить время выполнения.
Обращения к памяти: Минимизация числа обращений к памяти также позволит сократить время выполнения
Использование потоков: При возможности разделить код на независимые части, стоит использовать параллельное выполнение. Таким образом, программа не ждет выполнения одной из задач, а сразу переходит к следующей.
Также стоит обратить особое внимание на читаемость кода. Хорошо читаемый код не увеличивает производительность самой программы, зато увеличивает скорость работы разработчика, и влияет на качество исполняемой работы в целом.
Комфорт пользователя
Кроме всего прочего, пользователю должно быть комфортно при использовании приложения. Чтобы этого добиться, нужно обратить внимание на скорость загрузки приложения, частоту кадров.
«Секрет быстрой загрузки требует двух вещей: UPP (ощущаемая пользователем скорость) — это единственное, что имеет значение; эта скорость зависит от критического пути рендеринга (Critical Rendering Path). Критический путь — это единственный и необходимый код, который должен запускать перечисленные выше события». [3]
Таким образом, загружая только самое необходимое, программа будет иметь меньшее время отклика, а пользователю она будет казаться отзывчивее. Следующий шаг — частота кадров. Частота кадров — это частота, с которой система отрисовывает картинку приложения. В основном, все строится на восприятии человеческого глаза. Частоту желательно поддерживать высокую, для обеспечения плавности картинки. Тем не менее, глаз не воспринимает частоту выше 60Hz.
Поддержка
На протяжении жизненного цикла разработки также проводится совершенствование производительности. Появляются новые инструменты, технологии, обновления, все это может быть применено, положительно повлияв на эффективность программного продукта. Однако важнейшей частью процесса поддержки является исправление ошибок.
Несовершенство алгоритмов может приводить к неожиданным результатам. В книге Java: устранение проблем, приведен следующий пример:
«…однажды я отлаживал мобильное приложение, которое слишком быстро потребляло заряд батареи устройства. Это было приложение Android, использующее библиотеку, устанавливающую соединение с внешним устройством через Bluetooth. По какой-то причине эта библиотека создавала огромное количество потоков, но не закрывала их. Такие потоки, остающиеся открытыми и выполняющиеся без конкретной цели, называются потоками-зомби (zombie threads) и обычно становятся причиной проблем с производительностью и с использованием памяти. Кроме того, их, как правило, очень трудно анализировать». [4]
При большом размере кода становится достаточно тяжело искать ошибки. Для выполнения этой задачи используется отладчик — инструмент анализа, позволяющий пошагово выполнить операцию, показывая значения, содержащиеся в переменных. Встроенный отладчик есть во всех интегрированных средах разработки.
Задачи повышения производительности будут возникать на всех этапах жизненного цикла разработки приложения. В том числе и в процессе сопровождения. В процессе эксплуатации активно собирается информация о работе программного продукта и на ее основе вносятся правки.
Описанные в данной статье методы повышения производительности не являются исчерпывающими. Задача повышения производительности является комплексной и сложной. Всегда есть возможность улучшить работу программы в каком-то ее аспекте. Но не всегда есть такая необходимость, а порой незначительное улучшение может даться ценой падения производительности в целом. В конечном итоге, важнее всего в вопросе оптимизации производительности — это понимание поставленных задач и требуемого результата.
Литература:
1. Сравнение скорости работы языков программирования на примере решения задачи обучения нейронной сети // habr.com: [сайт]. URL: https://habr.com/ru/articles/497836/ (дата обращения: 02.11.2023).
- Д. Хайнеман Алгоритмы Справочник с примерами на С, C++, Java и Python / д. Хайнеман Г. Поллис, С Селков //: Пер. с англ. — Санкт-Петербург.: ООО “Альфа-книга”, 2017. — 432 с.
3. Основы производительности | MDN. — Текст электронный // developer.mozilla.org: [сайт]. URL: https://developer.mozilla.org/ru/docs/Web/Performance/Fundamentals (дата обращения: 02.11.2023).
- Спилкэ Лауренциу Java: устранение проблем. Чтение, отладка и оптимизация JVM-приложений / пер. с англ. А. В. Снастина. — М.: ДМК Пресс, 2023. — 356 с.: