Я младший разработчик программного обеспечения, и мне было интересно, когда будет наилучшее время для оптимизации программного обеспечения для повышения производительности (скорости).
Предполагая, что программное обеспечение не очень большое и сложное в управлении, лучше потратить больше времени на его оптимизацию или мне следует просто разработать программное обеспечение, которое правильно выполняет все функции, а затем приступить к его оптимизации для повышения производительности?
Ответы:
Номер один всегда и всегда должен быть читабельностью. Если он медленный, но читаемый, я могу это исправить. Если он сломан, но читабелен, я могу это исправить. Если это нечитаемо, я должен спросить кого-то еще, что это вообще должно было делать.
Удивительно, насколько быстрым может быть ваш код, когда вы сосредоточены только на удобочитаемости. Настолько, что я, как правило, игнорирую производительность, пока не получу повод для заботы. Это не должно означать, что меня не волнует скорость. Я делаю. Я только что обнаружил, что существует очень мало проблем, решения которых на самом деле быстрее, когда их трудно читать.
Только две вещи выводят меня из этого режима:
В любом случае, избегайте паралича анализа , заставляя себя думать, что не стоит пытаться найти решение, потому что оно может быть не самым быстрым. Ваш код действительно выиграет, если вы попробуете несколько решений, потому что внесение изменений заставит вас использовать дизайн, который облегчает изменение. Гибкая база кода может быть сделана быстрее позже, где это действительно необходимо. Выберите гибкий на скорости, и вы можете выбрать скорость, которая вам нужна.
источник
Если необходим определенный уровень производительности (нефункциональное требование), то это должно быть целью проектирования с самого начала. Например, это может повлиять на то, какие технологии могут быть подходящими или как вы структурируете поток данных в программе.
Но в целом невозможно выполнить оптимизацию до того, как будет написан код: сначала заставьте его работать, затем исправьте и, наконец, сделайте его быстрым .
Одна большая проблема с оптимизацией перед внедрением большей части функциональности заключается в том, что вы заперлись в неоптимальных дизайнерских решениях в неправильных местах. Часто (но не обязательно) компромисс между ремонтопригодностью и производительностью. Большинство частей вашей программы не имеют никакого отношения к производительности! Типичные программы имеют только несколько горячих точек, которые действительно стоит оптимизировать. Так что жертвовать ремонтопригодностью ради производительности во всех тех местах, где производительность не нужна, - это действительно плохая сделка.
Оптимизация для удобства обслуживания - лучший подход. Если вы потратите свое умение на ремонтопригодность и четкие конструкции, в конечном итоге вам будет легче определять критические участки и безопасно оптимизировать их, не ставя под угрозу общую конструкцию.
источник
Начните с того, что удалите из своего представления, что производительность - это то же самое, что и скорость. Производительность - это то, во что верит пользователь .
Если вы заставляете приложение реагировать в два раза быстрее на щелчок мыши, и вы переходите от десяти микросекунд к пяти микросекундам, пользователю все равно. Если вы заставляете приложение реагировать в два раза быстрее на щелчок мышью, и вы переходите от четырех тысяч до двух тысяч лет, опять же, пользователю все равно.
Если вы делаете свое приложение в два раза быстрее, и используете всю память на машине, и происходит сбой, пользователю все равно, что оно теперь в два раза быстрее.
Производительность - это наука об эффективных компромиссах в отношении потребления ресурсов для достижения определенного пользовательского опыта. Время пользователя является важным ресурсом , но оно никогда не бывает «быстрее». Достижение целей производительности почти всегда требует компромиссов, и они часто теряют время на пространство или наоборот.
Это ужасное предположение.
Если программное обеспечение не является большим и сложным в управлении, то оно, вероятно, не решает интересную проблему, которая волнует пользователя, и, вероятно, его очень легко оптимизировать.
Вы сидите там на пустой странице и пишете.
void main() {}
Вы начинаете оптимизировать? Там нет ничего, чтобы оптимизировать! Правильный порядок:Если вы попытаетесь сделать это в любом другом порядке, вы получите неправильный код, который является беспорядком, и теперь у вас есть программа, которая очень быстро выдает неправильные ответы и сопротивляется изменениям.
Но там не хватает шага. Реальное право заказа:
источник
Как правило, лучше оптимизировать производительность позже, но я видел, как многие проекты портятся, когда разработчики понимают, что они получили программное обеспечение, которое должно замедляться, когда к нему добавляется значительная нагрузка или данные.
Так что, на мой взгляд, лучше всего использовать подход среднего уровня; не придавайте этому особого значения, но не забывайте о производительности в целом.
Я приведу пример, который я видел много раз; учитывая библиотеку ORM, у нас есть объект User, который может иметь один или несколько заказов. Давайте зациклим все Заказы для Пользователя и выясним, сколько Пользователь потратил в нашем магазине - наивный подход:
Я видел, как разработчики пишут похожие вещи, не задумываясь о последствиях; сначала мы получаем пользователя, который, как мы надеемся, будет просто одним SQL-запросом к таблице User (но может включать в себя гораздо больше), затем мы перебираем заказы, что может включать получение всех соответствующих данных для всех строк заказа в заказе. , информация о продукте и т. д. - все это только для того, чтобы получить одно целое число для каждого заказа!
Количество запросов SQL здесь может вас удивить. Конечно, это зависит от того, как структурированы ваши сущности.
В этом случае правильный подход, скорее всего, заключается в добавлении отдельной функции для получения суммы из базы данных через отдельный запрос, написанный на языке запросов, предоставленном ORM, и я бы рекомендовал делать это в первый раз , а не откладывать это Для последующего; потому что если вы это сделаете, у вас, вероятно, будет гораздо больше проблем, и вы не будете уверены, с чего начать.
источник
Общая производительность системы является продуктом сложных взаимодействий всей совокупности компонентов системы. Это нелинейная система. Поэтому производительность будет зависеть не только от индивидуальных характеристик компонентов, но и от узких мест между ними.
Очевидно, что вы не можете проверить наличие узких мест, если все компоненты вашей системы еще не созданы, поэтому вы не можете действительно хорошо тестировать на ранних этапах. С другой стороны, после того, как система построена, может оказаться, что вам будет нелегко вносить изменения, необходимые для достижения желаемой производительности. Так что это костяк Catch-22 .
Чтобы усложнить ситуацию, ваш профиль производительности может резко измениться, когда вы переключаетесь на производственную среду, которая часто недоступна на ранних этапах.
Ну так что ты делаешь? Ну, несколько вещей.
Будьте прагматичны. На ранних этапах вы можете использовать функции платформы, которые являются «наилучшей практикой» для повышения производительности; например, использовать пул соединений, асинхронные транзакции и избегать сохранения состояния, что может привести к смерти многопоточного приложения, в котором разные работники борются за доступ к общим данным. Обычно вы не будете тестировать эти шаблоны на производительность, вы просто будете знать из опыта, что работает хорошо.
Будь итеративным. Принимайте базовые показатели производительности, когда система является относительно новой, и время от времени проводите повторное тестирование, чтобы убедиться, что вновь введенный код не сильно снижает производительность.
Не переоптимизируйте рано. Вы никогда не знаете, что будет важно, а что не будет иметь значения; Сверхбыстрый алгоритм синтаксического анализа строк может не помочь, например, если ваша программа постоянно ожидает ввода-вывода.
Особенно в веб-приложениях вы можете сосредоточиться не столько на производительности, сколько на масштабируемости. Если приложение может масштабироваться, производительность практически не имеет значения, поскольку вы можете продолжать добавлять узлы в свою ферму, пока она не станет достаточно быстрой.
Особое внимание уделяется базе данных. Из-за ограничений целостности транзакций база данных является узким местом, которое доминирует во всех частях системы. Если вам нужна высокопроизводительная система, убедитесь, что у вас есть талантливые люди, работающие на стороне базы данных, просматривая планы запросов и разрабатывая структуры таблиц и индексов, которые сделают обычные операции максимально эффективными.
Большинство из этих мероприятий не в начале или в конце проекта , но должно присутствовать , чтобы непрерывно .
источник
Поймите, что есть 2 очень разные крайности.
Первая крайность - это вещи, которые влияют на большую часть проекта, например, как разделить работу на количество процессов и / или потоков и как части взаимодействуют (сокеты TCP / IP? Прямые вызовы функций?), Следует ли реализовать расширенный JIT или интерпретатор "один код операции за один раз", или планировать ли структуры данных, чтобы они были пригодны для SIMD, или ... Эти вещи, как правило, оказывают сильное влияние на реализацию и становятся чрезмерно трудными / дорогостоящими для повторного подгонки после.
Другая крайность - это микрооптимизации - крошечные небольшие изменения повсюду. Эти вещи, как правило, почти не влияют на реализацию (и зачастую в любом случае лучше всего это делает компилятор), и тривиально выполнять такие оптимизации всякий раз, когда вам это нравится.
Между этими крайностями огромная серая зона.
То, к чему это действительно сводится, - это догадки об опыте / образованности, используемые для ответа на вопрос «оправдывают ли выгоды затраты». Для оптимизаций в / около одного предела, если вы часто ошибаетесь, это означает, что вы отбрасываете всю свою работу и перезапускаете с нуля или проваливаете проект (слишком много времени уходит на излишне сложный дизайн). В / около другого предела гораздо разумнее оставить его, пока вы не сможете доказать, что это имеет значение с помощью измерения (например, профилирование).
К сожалению, мы живем в мире, где слишком много людей думают, что оптимизация включает в себя (в основном не относящиеся к делу) вещи на «тривиальном» уровне.
источник
Проще всего написать код, который не является ни порформируемым, ни обслуживаемым. Сложнее написать порформантный код. Еще сложнее написать поддерживаемый код. И это самый трудный для написания кода, который является одновременно обслуживаемым и производительным.
Но легче сделать исполняемый код быстродействующим, чем сделать исполняемый код обслуживаемым.
Теперь, очевидно, это зависит от типа системы, которую вы делаете, некоторые системы будут сильно критичны по производительности и нуждаются в том, что планировалось с самого начала. Для таких чрезвычайно талантливых людей, как Эрик Липперт, который ответил выше, эти системы могут быть общими; но для большинства из нас они составляют меньшинство систем, которые мы строим.
Однако, учитывая состояние современного оборудования, в большинстве систем нет необходимости обращать особое внимание на оптимизацию с самого начала, а, скорее, достаточно избежать снижения производительности . Под этим я подразумеваю, что избегайте делать такие глупые вещи, как возвращение всех записей таблицы, чтобы получить счет, а не просто запрашивать
select count(*) from table
. Просто избегайте ошибок и старайтесь понять инструменты, которые вы используете.Затем, прежде всего, сконцентрируйтесь на поддержке вашего кода. Под этим я подразумеваю:
Поддерживаемый код гораздо проще оптимизировать, если статистика показывает, что это необходимо.
Далее, убедитесь, что ваш код имеет много автоматических тестов, это имеет несколько преимуществ. Меньше ошибок означает больше времени для оптимизации, когда это необходимо . Кроме того, когда вы оптимизируете, вы можете выполнять итерации и находить лучшее решение гораздо быстрее, поскольку вы обнаруживаете ошибки в своих реализациях гораздо быстрее.
Сценарии автоматического развертывания и инфраструктура сценариев также очень полезны для настройки производительности, поскольку, опять же, они позволяют выполнять итерации быстрее; не говоря уже о его других преимуществах.
Так что, как всегда, есть исключения (которые вам понадобятся для более точной идентификации), но, в общем, мой совет: во-первых, изучите свои инструменты и избегайте узких мест в производительности кодирования. Во-вторых, убедитесь, что ваш код поддерживается. В-третьих, автоматизированные тесты. В-четвертых, полностью автоматизированное развертывание. Только после того, как все это будет сделано, вы должны беспокоиться об оптимизации.
источник
Я мог бы быть предвзятым, работая в областях, очень критичных к производительности, таких как обработка изображений и трассировка лучей, но я все же сказал бы, чтобы оптимизировать «как можно раньше» . Независимо от того, насколько критичны ваши требования к производительности, после оценки всегда намного больше информации и ясности, чем заранее, что означает, что даже самые эффективные оптимизации обычно применяются позже после получения таких знаний.
Особые случаи
Но иногда «как можно позже» все еще чертовски рано в некоторых особых случаях. Например, если мы говорим офлайн-рендерерах, то структуры данных и методы, которые вы используете для достижения производительности, на самом деле проникают в пользовательский дизайн., Это может показаться отвратительным, но поле настолько ультрасовременное и настолько критичное к производительности, что пользователи принимают пользовательские элементы управления, специфичные для методов оптимизации, применимых к конкретному raytracer (например, кэширование освещенности или картирование фотонов), поскольку некоторые из них используются часы ожидания для рендеринга изображения, а другие привыкли выплачивать огромные суммы денег для аренды или владения фермой рендера с машинами, предназначенными для рендеринга. Для этих пользователей существует значительное сокращение времени и денег, если конкурентный офлайн-рендеринг может предложить нетривиальное сокращение времени, затрачиваемого на рендеринг. Это своего рода область, где сокращение времени на 5% действительно волнует пользователей.
В таких специфических случаях вы не можете просто выбрать один метод визуализации и надеетесь оптимизировать его позже, так как весь проект, включая пользовательский дизайн, вращается вокруг структур данных и алгоритмов, которые вы используете. Вы не можете даже просто идти с тем, что хорошо сработало для других людей, поскольку здесь, вы, как личность, и ваши конкретные сильные и слабые стороны, в значительной степени влияете на создание конкурентного решения. Мышление и чувствительность основного разработчика, стоящего за Арнольдом, отличаются от тех, кто работает над VRay, которые использовали совсем другой подход; они не могут обязательно поменяться местами / техниками и выполнять лучшую работу (даже при том, что они оба промышленные лидеры). Вы должны что-то вроде эксперимента, прототипа и теста и найти то, что Особенно хорошо это делать, учитывая бесконечное множество передовых технологий, если вы надеетесь выпустить что-то конкурентоспособное, что на самом деле будет продаваться. Таким образом, в этом особом случае проблемы с производительностью выходят на передний план, как, пожалуй, самая важная проблема еще до начала разработки.
Тем не менее, это не обязательно является нарушением оптимизации «как можно позже» , просто «как можно позже» довольно рано в этих крайних и специфических случаях. Выяснение того, когда, а также что не требует таких ранних проблем с производительностью, если вообще когда-либо, является, вероятно, главной проблемой для разработчика. То, что не нужно оптимизировать, может быть одной из самых ценных вещей для изучения и продолжения обучения в карьере разработчика, так как вы не найдете недостатка в наивных разработчиках, которые хотят все оптимизировать (и, к сожалению, даже ветеранов, которым удалось как-то сохранить свою работу в несмотря на их контрпродуктивность).
Как можно позже
Возможно, самая трудная часть состоит в том, чтобы попытаться понять, что это значит. Я все еще учусь и программирую почти три десятилетия. Но особенно сейчас, в третьем десятилетии, я начинаю понимать, что это не так сложно. Это не ракетостроение, если вы сосредоточены больше на дизайне, чем на реализации. Чем больше ваши проекты оставят перед вами пространство для соответствующей оптимизации без изменений в дизайне, тем позже вы сможете оптимизировать. И все больше и больше производительности я приобрел, ища такие конструкции, которые предоставляют мне эту передышку.
Дизайн, который предлагает передышку для оптимизации позже
Эти типы конструкций на самом деле не так сложны в большинстве случаев, если мы можем применить некоторый «здравый смысл». Как личная история, я увлекаюсь изобразительным искусством как хобби (мне кажется, это несколько помогает программировать программы для художников, которые сами понимают их потребности и говорят на их языке), и я провел некоторое время в начале 2000-х, используя апплеты Oekaki. онлайн как быстрый способ рисовать и делиться своими работами и общаться с другими художниками.
В частности, мой любимый сайт и апплет были пронизаны недостатками производительности (любой нетривиальный размер кисти замедлял бы сканирование), но имел очень хорошее сообщество. Чтобы обойти проблемы с производительностью, я использовал маленькие 1 или 2-пиксельные кисти и просто набросал свою работу так:
Тем временем я продолжал давать автору предложения по улучшению производительности, и он заметил, что мои предложения носили сугубо технический характер, говоря об оптимизации памяти, алгоритмах и так далее. Поэтому он на самом деле спросил, был ли я программистом, и я ответил «да», и он пригласил меня поработать над исходным кодом.
Поэтому я посмотрел на исходный код, запустил его, профилировал, и, к своему ужасу, он разработал программное обеспечение на основе концепции «абстрактного пиксельного интерфейса»
IPixel
, который, в конечном итоге, стал основной причиной самых популярных горячих точек для всего с динамическим выделения и рассылка для каждого пикселя каждого изображения. Тем не менее, не было никакого практического способа оптимизировать это, не пересматривая весь дизайн программного обеспечения, потому что дизайн загнал его в угол, где нет ничего сверх самой тривиальной микрооптимизации, когда наши абстракции работают на уровне детализации одного абстрактного пикселя. и все зависит от этого абстрактного пикселя.Я думаю, что это нарушение "здравого смысла", но, очевидно, это не было таким здравым смыслом для разработчика. Но это все равно, что не абстрагировать вещи на таком детальном уровне, когда даже самые базовые сценарии использования будут создаваться миллионами, например, пикселями, частицами или крошечными единицами в гигантском армейском симуляторе. Благожелательно к
IImage
(вы можете обрабатывать все форматы изображение / пиксельные нужно при этом громоздкий агрегированного уровня) илиIParticleSystem
доIPixel
илиIParticle
, а затем вы можете поместить в самом основных и быстро к записи и простым для понимания реализации позади таких интерфейсов и имейте всю передышку, которую вам когда-либо потребуется оптимизировать позже, не пересматривая весь дизайн программного обеспечения.И это цель, как я вижу это в эти дни. За исключением особых случаев, таких как офлайн-рендеры, описанные выше, проектируйте с достаточным количеством передышек, чтобы оптимизировать их как можно позже, с максимально возможной ретроспективной информацией (включая измерения), и применяйте любые необходимые оптимизации как можно позже.
Конечно, я не обязательно предлагаю начинать с использования квадратичных алгоритмов сложности для входных данных, которые легко достигают нетривиального размера в обычных случаях пользовательского конца. Кто это делает? Но я даже не думаю, что это настолько важно, если реализацию легко заменить позже. Это все еще не серьезная ошибка, если вам не нужно пересматривать какие-либо проекты.
источник
Это зависит от того, что эта производительность означает для вашего приложения. И от того, возможно ли вообще оптимизировать производительность до того, как ваше приложение будет функционально завершено.
Чаще всего вам не следует беспокоиться об этом, пока у вас нет ничего лучше, но может случиться так, что определенный уровень производительности имеет решающее значение для успеха вашего приложения. Если это так, и вы подозреваете, что это может быть нелегко, вы должны начать смотреть на производительность ради «быстрого провала».
Важный принцип любого проекта - сначала сосредоточиться на сложных деталях. Таким образом, если окажется, что вы не можете этого сделать, вы узнаете об этом раньше, и у вас будет время попробовать что-то совершенно другое, или проект может быть отменен, прежде чем на него будет потрачено слишком много.
источник
Я собираюсь предложить производительность больше, чем скорость. Он включает в себя масштаб (от сотен до тысяч одновременно работающих пользователей). Конечно, вы не хотите, чтобы приложение работало, когда оно загружается. Производительность включает в себя, сколько ресурсов (например, памяти) потребляет приложение.
Производительность также простота использования. Некоторые пользователи предпочитают, чтобы одно нажатие клавиши выполняло задачу за 10 секунд, чем два нажатия клавиши выполняли бы задачу за 1 секунду. Для такого рода вещей попросите вашего дизайн лидера. Я не хотел бы так рано рассказывать пользователям о подобных вещах. В вакууме они могут сказать X, но как только они работают с функциональной предварительной версией, они могут сказать Y.
Лучшая индивидуальная скорость - удерживать ресурс, такой как соединение с базой данных. Но для масштабирования вы должны получить соединение как можно позже и освободить его как можно скорее. Одна поездка в базу данных, чтобы получить 3 вещи, быстрее, чем 3 отдельных поездки в базу данных.
Вы совершаете поездки за информацией, которая не меняется во время сеанса. Если это так, получите его в начале сеанса и удерживайте его в памяти.
При выборе типа коллекции учитывайте функциональность, скорость и размер.
Вы уверены, что вам нужно держать предметы в коллекции? Распространенной проблемой является чтение всех строк из файла в список, а затем обработка списка по одной строке за раз. Гораздо эффективнее читать файл по одной строке и пропустить список.
Ты зациклишься три раза, когда сможешь зациклить один раз и сделать три вещи.
Есть ли место, где вам может потребоваться обработка в другом потоке с обратным вызовом. Если это так, упакуйте код с учетом этой возможной необходимости, если он не мешает непосредственным потребностям проектирования.
Высокая производительность также является чистым кодом.
Есть преждевременная оптимизация, и есть просто работа со здравым смыслом, которая на самом деле не занимает больше времени.
В базе данных я вижу преждевременную оптимизацию. Будет нормализовать скорость, прежде чем возникнет проблема со скоростью. Аргумент, который я получаю, состоит в том, что если мы изменим таблицу позже, тогда мы должны изменить все. Зачастую вы можете создать представление, представляющее данные таким образом, и его, возможно, потребуется заменить на ненормализованную таблицу позже.
источник