Як виміряти складність на практиці у вашому великому програмному проекті?


11

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

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

Чи можна це зробити? Або люди на практиці просто покладаються на "локально", використовуючи швидкий алгоритм, щоб зробити всю програму швидшою, а не глобально розглядати додаток у цілому?

(Тому що мені здається нетривіальним, щоб показати, що якщо ви збираєте велику кількість алгоритмів, які, як відомо, дуже швидко самостійно, ви також закінчуєте швидку програму в цілому.)

Я запитую це, бо мені доручено прискорити великий проект, який написав хтось інший, де багато алгоритмів взаємодіють і працюють над вхідними даними, тому мені незрозуміло, як швидше впливати на створення одного алгоритму вся програма.


1) Для цього потрібен підхід тестування, щоб знайти моменти, які слід вдосконалити. Тестування тестування, Тестування на міцність, Динамічне тестування (за допомогою моніторингу метрики / показників процесора кожного компонента). 2) Після пошуку балів, які потрібно покращити, ви знайдете першопричину цих балів. 3) Знайдіть рішення для вирішення першопричини, зберігаючи правильність.
переобмін

вам потрібні деякі інструменти для цих тестів, згаданих у пункті 1
переобмін

1
Аналіз Big O не говорить про те, як працює алгоритм. Це говорить про те, як продуктивність буде масштабуватись із nзбільшенням.
Джон Ву

Відповіді:


5

Великі програмні проекти складаються з багатьох різних компонентів, і не всі вони, як правило, є вузьким місцем. Зовсім навпаки: майже для будь-якої програми, що бачила в моєму житті, де низька продуктивність була проблемою, застосовувався принцип Парето : понад 80% підвищення продуктивності можна досягти, оптимізуючи менше 20% коду (насправді я думаю, що їх цифри часто перевищували 95% до 5%).

Тож почати розгляд окремих творів часто є найкращим підходом. Ось чому профілювання (як пояснено у відповіді Девіда Арно ) чудово, оскільки воно допомагає визначити згадані 5% коду, де оптимізація дасть вам "найбільший удар за долар". Оптимізація "всієї програми" несе певний ризик перенапруження, і якщо ви оптимізуєте ці 95% навіть у 10 разів, це часто не матиме вимірюваного ефекту. Зауважимо також, що профілювання говорить вам набагато більше, ніж будь-яка оцінка складності гіпотетичного алгоритму, оскільки простий алгоритм, який потребує кроків O (N ^ 3), все ще може бути швидшим, ніж складний алгоритм, для якого потрібен O ​​(N log (N)), поки N досить малий.

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

Типові методи оптимізації включають

  • вдосконалення використання алгоритмів та структур даних

  • тонка настройка колишнього

  • мікрооптимізація на деяких реальних гарячих точках

  • перекодування критичних розділів за допомогою монтажного коду або CUDA

Зауважте, ці методи працюють на різних рівнях абстракції, деякі з них переглядають компонент більше "в цілому", ніж інші. Отже, це залежить від того, що ви маєте на увазі під "все, що ми робимо, - це переглядати окремі фрагменти" - якщо ви мали на увазі лише мікрооптимізацію, я не погоджуюся з тим, що "ми" працюємо лише над цим. Але якщо ви маєте на увазі застосувати ці повномасштабні оптимізації для ізольованих частин або компонентів, то, мабуть, "ми" працюємо над правильними деталями, і вам слід поставити під сумнів свої очікування.


13

Стандартний, перевірений спосіб - це профілювання коду . Ви виконуєте динамічний аналіз запущеної системи для вимірювання часу, використання пам'яті тощо. Потім аналізуєте результати, щоб знайти вузькі місця.

Ці вузькі місця потім експериментально переписують, а результат ще раз переробляють, щоб визначити, що було досягнуто збільшення швидкості, зменшення використання пам'яті тощо. Потім цей процес повторюється до досягнення прийнятного підвищення продуктивності.


1
Це вирішує проблему продуктивності, тому ми це робимо, але не відповідає на початкове запитання. Думаю, що в найгіршому випадку складність часу або простору найкраще було б з'ясувати за допомогою інструмента аналізу статичного програмного забезпечення, який може бути відсутнім. Тести на ефективність чудово підходять для конкретних сценаріїв, але вони не розповідають багато про найгірші можливі ситуації.
Френк Хілеман

3
@FrankHileman Я думаю, що справа тут у тому, що продуктивність є практичною проблемою і може бути виміряна лише практично. Ви не використовуєте математику, щоб знайти вузьке місце свого програмного забезпечення, навіть якщо ви могли вирішити його, знайшовшись за допомогою математики (алгоритми).
Wildcard

У відповідній примітці, в старій презентації слайд-шоу (скляні слайди) існувала ціла прикинута технологія того, як ретельно обчислити середню густину слайда ліхтаря математично, щоб визначити яскравість світла, що використовується. Цілком марно: якщо малюнок не відображається добре, ви отримуєте яскравіше світло!
Wildcard

@Wildcard Хоча продуктивність можна виміряти лише під час виконання, її можна передбачити статично. Неправильний вибір структури даних може виглядати добре, ефективніше, в тестах на ефективність, але в нещасних випадках не вдається мати кращі випадки, які можна було б передбачити в статичному аналізі. Це та сама причина, коли ми розглядаємо загальний аналіз складності для структур даних загалом.
Френк Хілеман

@Wildcard: ти маєш рацію, однак Френк також дуже правильний, що ця публікація не відповідає на питання.
Док Браун

3

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

Першим моїм кроком було б отримати свої руки на детальній архітектурній схемі або створити її самостійно. З’ясуйте, які кроки виконуються за допомогою компонентів програмного забезпечення та скільки часу займає кожен крок.

Також з’ясуйте, як компоненти взаємодіють між собою. Це може змінити все.

Наприклад, я бачив код на C #, де інтерфейс між двома компонентами передавав IEnumerable, побудований першим компонентом, який потім перераховувався другим компонентом. У C # це вимагає переключення контексту, що може бути дорого за певних обставин. Розв’язання не впливає на алгоритм. Простий .ToList () переконайтеся, що результат зібраний до наступного кроку вирішує цю проблему.

Інша річ, яку слід врахувати, це вплив на систему, на якій ви запускаєте код. Взаємодія обладнання, очевидно, може бути фактором у складних системах. Шукайте IO для дисків, великих розмірів пам'яті та мережевого IO. Іноді їх можна вирішити ефективніше, налаштувавши систему або навіть замінивши апаратне забезпечення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.