Чому я повинен дбати про мікропродуктивність та ефективність?


71

Багато питань та відповідей на сторінках C / C ++, конкретно чи опосередковано обговорюють проблеми мікроефективності (наприклад, накладні витрати на функцію непрямого проти прямого та вбудованого) або використання алгоритму O (N 2 ) проти O (N log N) на список 100 предметів

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

Моє запитання: чому так багато піклується велика кількість програмістів? Це справді проблема для більшості розробників, мені просто пощастило, щоб не надто переживати про це, чи я поганий програміст?


5
+1, хороше загальне запитання.
iammilind

+1 хороше запитання ... Я додав 2 теги .. сподіваюся, що ви не заперечуєте з цього питання.

2
Я очолюю дві великі цитати 1) "Передчасна оптимізація - корінь усього зла". 2) 80% вашого часу буде витрачено на 20% вашого коду (правило 80/20).
Джеймс Хоурі

2
Я помічаю пару відповідей, які розповідають про мій приклад O (n * n). Я чітко вказав список із 100 предметів, але вони все ще наполягають на тому, що O (nlogn) є кращим, явно заявляючи про поліпшення продуктивності, якщо список, у майбутньому, перейде до 1000-х чи мільйонів. Це одержимість мікрооптимізації, оскільки програмісти програмують можливі майбутні вимоги, а не актуальні вимоги до лікування (Де я чув це раніше ...)
mattnz

5
@James повна цитата Дональда Кнута: "Ми повинні забути про малу ефективність, скажімо, про 97% часу: передчасна оптимізація - корінь усього зла". Буде кілька хороших відповідей про решту 3% у цій темі.
StuperUser

Відповіді:


14

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

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

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


6
Ще один: ініціалізаційний код, який виконується один раз, зазвичай не потребує оптимізації, тому шукайте в іншому місці.
Майк Десимоне

3
Залежить від того, як часто буває "раз". Під час запуску ./configureя б ризикнув сказати, що до 75% часу запуску може бути витрачено на "ініціалізацію" коду в програмах, за допомогою яких виконується сценарій. 25-50% можуть бути витрачені навіть на динамічні зв'язки.
Р ..

12
Правило А - жахливе правило. Архітектура системи відіграє важливу роль у продуктивності, і якщо ви дізнаєтесь згодом, ваша архітектура просто не може підтримувати ваші вимоги до продуктивності, ви, в основному, накручені. Отже, хоча ви зможете передати дрібні деталі, повністю ігноруючи це на початку, це просто неправильно.
edA-qa mort-ora-y

3
@ edA-qa: Раніше я так думав, але з роками переживало чимало інших проектів, які стискаються або провалюються, перш ніж будь-які міркування щодо продуктивності стали проблемою. Кожен раз, коли у мене виникали проблеми з ефективністю, виправлення було порівняно низькою вартістю, днями або кількома тижнями. Більше проблем, ніж будь-який інший «помилка», виявив виправлення в розробці. Однак, як і будь-який товарний елемент ризику, конуси продуктивності повинні бути визначені та пом'якшені на початку проекту.
mattnz

5
ОП запитала, чому так багато піклується, і я не бачу, як ця відповідь насправді відповіла на питання, якщо тільки ОП не зацікавилося почути, щоб хтось сказав "не хвилюйся про це!".
червоний бруд

54

Я думаю, що все у вашому списку - це мікрооптимізація, на яку взагалі не слід дивитися, за винятком

використовуючи алгоритм O (n * n) проти O (NlogN) у списку 100 елементів

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

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


36
+1 для "Вибір правильного алгоритму ніколи не є мікрооптимізацією".

9
Я також поставив +1, але зауважте, що вибір оптимального алгоритму великого O, коли розміри даних, безумовно, невеликі, може завдати шкоди часу розробки, розміру програми та, можливо, навіть використанню пам'яті. Якщо ви сортуєте покерні руки, чи справді ви хочете написати квертс, гладкий корт або злиття? Я б почав з простого сортування вставки або використання сортувальної мережі.
Р ..

8
Забавно. У нитці про мікрооптимізацію багато коментаторів мікрооптимізують відповіді. ;)
Безпечний

5
"Я хотів би зробити ставку незабаром, що той самий код буде повторно використаний для декількох мільйонів рядків": Це повністю залежить від проблемної області. Приклади: якщо ви пишете шаховий алгоритм, ви можете бути впевнені, що розмір дошки не зміниться. Якщо ви програмуєте автономне транспортний засіб, кількість коліс не буде рости , що швидко, або.
nikie

3
Мені не подобається "вибір правильного алгоритму ніколи не є мікрооптимізацією", оскільки це ОБОВ'ЯЗКОВО правдиво, враховуючи характер слова "правильно". Однак я відчуваю, що ваше значення - це дійсно "найшвидший або найефективніший" алгоритм, з яким я не згоден. Вибір найефективнішого алгоритму - неправильний вибір, якщо для впровадження потрібні багато часу, а швидкість чи простір цього сегмента навряд чи має значення.
Кейсі Паттон

18

Час тому назад, на своїй першій роботі, я написав код для вбудованих систем. Ці системи використовували 8086 мікропроцесорів і мали обмежену пам’ять. Ми використовували компілятор Intel C. Одна система, яку я побудувала, потрібна для доступу до 3-денного масиву структур. Я побудував його так, як мені сказала книга: зателефонуйте malloc на 3 виміри, потім виділіть рядки для наступного виміру, потім calloc для кінцевих вузлів.

Це було досить складно (для мене на той час), мені довелося робити підгонку кривих, контроль процесу ANOVA та аналіз Chi-квадрата. Не було бібліотек, які це робили для нас; нам довелося все це написати і помістити все на 8086.

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


В іншому випадку на тій самій роботі замовник скаржився на час реакції у своїй системі контролю статистичних процесів. Команда до мене розробила систему «програмного ПЛК», де оператори могли використовувати булеву логіку для комбінування сигналів та відключення комутаторів. Вони написали це спрощеною мовою, що ми сьогодні би називали "доменною мовою". наскільки я пам’ятаю, це виглядало тощо ((A1 + B1) > 4) AND (C1 > C2).

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

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

Новий код був не настільки ретельним, оскільки я створив спеціальний компілятор . Але перевага в експлуатаційних характеристиках добре переважала недолік у обслуговуванні.


Зовсім недавно я працював над системою, яка потребувала динамічного розбору льоту XML. Більші файли займуть значно більше часу. Це було дуже чутливим до продуктивності; занадто повільний розбір може призвести до того, що інтерфейс користувача стане абсолютно непридатним.

Такі речі постійно з’являються.


Тож .... іноді вам потрібен бездоганний, простий у написанні код. Іноді потрібно, щоб код запускався швидко. Компроміс - це інженерне рішення, яке потрібно прийняти для кожного проекту.


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

6
@CodeInChaos: Відповідь не вимагає іншого. Це відповідає на питання ОП "Чому мені слід піклуватися про мікропродуктивність та ефективність?" Питання, що стосуються попередньої оптимізації, були лише вирішені іншими відповідями.
webbiedave

12

Якщо ви обробляєте великі зображення та повторюєте кожен піксель, то налаштування продуктивності може бути вирішальним.


2
+1 - також високочастотне фінансування, будь-який аудіо / відео кодер / декодер, моделювання та моделювання (наприклад, ігри), загальносистемні біти на зразок планувальників процесора та менеджерів пам'яті тощо.
Біллі ONeal

3
МОЖЕ бути критичними, але IS критичним тільки після того, як ви довели , що це так і ви профільований його там , де ви думаєте , що проблема є. (Підказка: його, мабуть, немає.)
ДАЙТЕ МОЕ правильне ДУМКА

2
@ Справедливий мій правильний висновок: насправді для обробки зображень обробка даних зазвичай є другим за величиною споживачем часу (введення-виведення все ще є найбільшим). Однак оптимізація вводу / виводу вимагає багато незвичайних / шалених конструкцій та їх прийняття колегами-програмістами, а іноді це неможливо вдосконалити. Однак обробна частина, як правило, незрівнянно паралельна, отже, вони легко отримують переваги. (Налаштування одного може бути сприйняте іншим як пряма реалізація підручника ... якщо ви не досягнете рівня VirtualDub)
rwong

12

Дозвольте трохи розповісти про те, чому стоїть культура.

Якщо вам ближче 40, ніж 20, і ви програмували на життя на дорослі роки, тоді ви досягли віку, коли C ++ справді була єдиною грою в місті, настільні програми були нормою, а обладнання все ще сильно відстає програмне забезпечення з точки зору пропускної здатності / можливостей продуктивності.

  • Ми звикли робити дурні фокуси програмування, щоб мати можливість читати великі (> 2G) файли ...
  • Ми звикли турбуватися про розмір виконавчого файлу ...
  • Ми звикли турбуватися про те, скільки пам'яті споживають наші програми ...
  • Ми регулярно приймали алгоритмічні часові та космічні рішення ...
  • Навіть на задньому плані нам доводилося писати програми CGI на C або C ++, щоб нічого не можна було обробити. RPS ... Це було на кілька порядків швидше.
  • Ми використовували тести на предмет ефективності між delphi / c ++ / vb!

Дуже мало людей сьогодні турбуються про ці речі.

Однак 10 років тому вам все одно доводилося турбуватися про те, щоб ваше програмне забезпечення завантажувалося через 56 кбіт модем і працювало на 5-річному ПК ... Пам’ятаєте, наскільки шалені ПК були в 1996 році? Подумайте про 4 Гб жорсткого диска, 200 МГц процесора та 128 Мб оперативної пам'яті ...

А сервери 10 років тому? Сервер Dell "наступного покоління" коштував 2000 доларів і постачався з 2 (!) Процесорними процесорами 1 ГГц, 2 Гбіт або Рам і жорстким диском 20 Гб.

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


1
Додаткові 20-річний досвід також означає, що ми отримали опіки від того, що пройшли процес оптимізації багато, багато разів і уникаємо робити те, що може знадобитися згодом. З тієї ж причини, коли я не плескаю великий палець (сильно), використовуючи молоток.
Blrfl

1
петля розмотування <shudder>
red-dirt

5
і сьогодні всі діти, які вважали, що пропускна здатність, процесор і пам’ять є необмеженими, знаходять, що їхні мобільні додатки працюють не дуже добре.
gbjbaanb

9

тут вже є 10 відповідей, і деякі справді хороші, але тому, що це моя особиста домашня улюблениця ...

передчасна оптимізація, яка a) потребує більше часу, ніж простого рішення b) вводить більше коду, де просте рішення було б удвічі меншим, а наполовину складніше і c) робить речі менш читабельними, АБСОЛЮТНО слід уникати. Однак якщо розробник має вибір між використанням std :: map або std :: vector, і він вибирає неправильну колекцію з чистого незнання для продуктивності, що так само погано, якщо не гірше, ніж передчасна оптимізація. Що робити, якби ви могли трохи змінити свій код сьогодні, зберегти читабельність, зберегти таку ж складність, але зробити це більш ефективним, чи зробите ви це? Або ви б це назвали "передчасною оптимізацією"? Я вважаю, що багато людей навіть не думали б так чи інакше.

Колись я був тим хлопцем, який порадив "мікрооптимізацію", яка вимагала дуже незначних змін, і мені дали таку ж відповідь, що і ви сказали: "Не варто занадто рано оптимізувати. Давайте просто почнемо працювати, і ми змінимо її пізніше, якщо є проблема з продуктивністю ". Пройшло кілька релізів, перш ніж ми її виправили. І так, це була проблема виступу.

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

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

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


+1: Це один із факторів працевлаштування для тих, кого найняли розробляти програмне забезпечення Shrinkwrap та комерційні веб-сайти . Профілактика менш затратна, ніж прокляття замовника.
rwong

6

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

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


1
+1 - Примітка: Більшість запитань SO із тегом "performance", ймовірно, є частиною помилки вибірки: P
Billy ONeal

3
Я впевнено бачу тут прокляте безліч питань щодо передчасної оптимізації ... Я думаю, що це випливає з того, що багато програмістів-любителів починають з ідеї писати ігри, і є величезний корпус нісенітницької "оптимізації" книг і веб-сайти, пов’язані з розвитком ігор, які вкладають погані ідеї в голови початківців. :-)
R ..

4
Якщо ви маєте справу з чимось хитрим, часто здається, що простіше відпочити від хитрої проблеми та розчарувати час, переживаючи, чи варто вам скористатися, i++або++i
Carson63000

@ Carson63000: так, це могло б повністю перекривити зразки. Або вони витрачають час, відповідаючи на питання, чому моє operator ++не складено.
rwong

4

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

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

Щоб заощадити гроші, вони можуть мати кількість спалаху (для зберігання коду) та оперативної пам’яті, які здаються крихітними для тих, хто лише написав код для ПК або смартфонів. Для економії енергії вони можуть працювати при порівняно низькій тактовій частоті.

Для прикладу сімейство мікроконтролерів STM32 йде від 24 МГц, 16 Кб спалаху та 4 КБ оперативної пам’яті , до 120 МГц, 1 Мб спалаху та 128 КБ оперативної пам’яті .

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


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

2

Це є по суті мовами низького рівня, коли один працює в патологічний випадок продуктивності , де одна деталі , яка не має значення 99% від часу викликає в вузькому місці , один на самому справі має можливість працювати безпосередньо навколо питання ( в відміну від більшості інших мови); але, звичайно, часто, як це зробити найбільш ефективно, не відразу видно. Звідси половина дивних / цікавих питань щодо мікрооптимізації, заданих тут.

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


+1: варто зазначити, що "патологічний показник" може трапитися з будь-яким у світі, незалежно від мови та платформи. Можливість повторної реалізації мовою нижчого рівня для тестування та читання розбирання може забезпечити більше уявлень , але не завжди забезпечує працездатне рішення. Приклад: "Я знаю, що можу це зробити в зборі - але це потрібно працювати в середовищі часткової довіри!"
rwong

2

Продуктивність завжди є гарячою темою, коли ви маєте справу з C та C ++. Що стосується того, як далеко слід пройти, ви завжди можете зійти з розуму до точки вбудованого ASM або використовувати арифметику вказівника для більш швидкої ітерації. Однак настає момент, коли витрачається стільки часу на оптимізацію, що робота над розробкою загальної програми припиняється.

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

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

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


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

арифметика вказівника не швидша, ніж ш / е.

2

Чому програмісти так хвилюються? Існують нерозумні ідеї, що заповнюють їх голови, такі як вирішення проблем із виконанням результатів, перш ніж вони знають, що вони їх мають, і не розуміючи, коли вони здогадуються .

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

Однак, метод, який я використовую, схожий на ваш, але не той самий:

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

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

Ось приклад, що я маю на увазі.


1

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

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

Ранні програмісти MIT не були народжені, щоб робити приголомшливі речі; Вони почали спрощувати та живити існуючі алгоритми. Їх гордістю було те, що змусити 2 + 2 дати на чотири за дві секунди менше, ніж існуючий алгоритм (це лише приклад, ти розумієш). Вони постійно намагалися використовувати менше перфокарт у своїх машинах TI-83 для продуктивності.

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

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


1
Я не думаю, що програміст-любитель не має нічого спільного з цим. Тільки тому, що ти не робиш щось професійно, не обов'язково означає, що ти маєш весь час у світі витрачати на це. Більше того, більшість любителів збираються робити більші помилки, такі як вибір неправильних алгоритмів, ніж більшість справжніх професіоналів. Більше того, професіонал, напевно, працює над продуктом, який обробляє значно більше даних, ніж хобіст (який, отже, повинен бути швидшим), і повинен тримати клієнтів задоволеними роботою програми. У любителів таких обмежень немає.
Біллі ONeal

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

3
Я б стверджував протилежне. У мене є 8 годин і більше в день, щоб працювати над чимось професійним. Я отримую 1, може, 2 години на день для своїх хобі-проектів.
Біллі ONeal

1

використовуючи алгоритм O (N2) проти O (NlogN) у списку 100 предметів.

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

Мені потрібно було сортувати цей список. Виявляється, замінивши std::sortна сортувальну мережу (по суті, багато вкладених if), відганяли великий відсоток часу роботи (я не пам'ятаю кількість, але це було щось на зразок 10–20%). Це величезна перевага мікро-оптимізації, і код абсолютно критичний для продуктивності.

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


1

Кумулятивне використання енергії

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

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

Але коли десятки тисяч, а то й мільйони користувачів в деяких випадках використовують ваш код, все це додаткова неефективність накопичується. Якщо ваш інструмент перешкоджає процесору переходити у стан сну всього десять секунд на день, і мільйон користувачів користуються ним, ваш неефективний алгоритм просто витрачав додаткові 140 кВт * год [1] на день.

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


[1] Я щойно зробив це, 10 мільйонів секунд, 50 Вт. Точна цифра залежить від багатьох речей.


1
Слід почати відразу, згадуючи чарівне слово "мобільний". Під час роботи на настільній платформі додаток, який потребує 1 / 100сек процесорного часу, щоб намалювати кадр 60 разів в секунду, буде "досить швидким"; покращення продуктивності вдесятеро зробило б нульову різницю для користувача. Однак на мобільній платформі додаток, що працює на 90% використання процесора, може заряджати батареї набагато швидше, ніж на 10%.
supercat

1

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

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

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

Тож у моєму випадку найважливішими та найпоширенішими оптимізаціями часто є представлення даних та макети пам'яті, багатопотоковість та SIMD (як правило, у такому порядку, при цьому подання даних є найважливішим, оскільки це впливає на можливість двох останніх). Я не стикаюся з такою кількістю проблем, які вирішуються деревами, хеш-таблицями, алгоритмами сортування та подібними речами. Мій щоденний код більше в дусі: "для кожної речі щось роби".

Звичайно, це ще один випадок поговорити про те, коли необхідні оптимізації (а ще важливіше, коли їх немає), мікро- або алгоритмічні. Але в моєму конкретному випадку, якщо критичний шлях виконання потребує оптимізації, 10-кратне підвищення швидкості часто досягається за допомогою оптимізації на рівні мікрорівнів, таких як багатопотокове читання, SIMD та перестановка макетів пам’яті та шаблонів доступу для поліпшення місцевості посилання. Не так часто мені доводиться, скажімо, замінювати сортування міхурів інтросортом або сортуванням радіації або виявленням зіткнення квадратичної складності з BVH, настільки, щоб знайти гарячі точки, які, скажімо, виграють від розщеплення гарячого / холодного поля.

Тепер у моєму випадку моє поле є настільки критичним для продуктивності (променеві трейсінг, фізичні двигуни тощо), що повільний, але ідеально правильний промінь, який потребує 10 годин для зображення, часто вважається марним або швидшим, ніж швидкий, який є повністю інтерактивним, але виводить найпотворніші зображення, коли промені проникають скрізь через відсутність водонепроникного променя / три перетину. Швидкість, мабуть, є первинною метрикою якості такого програмного забезпечення, імовірно, навіть більше, ніж коректність до певного моменту (оскільки "правильність" - нечітка ідея з прокручуванням, оскільки все наближається до тих пір, поки воно не відбувається збою чи щось подібне). І коли це так, якщо я не думаю про ефективність наперед, я вважаю, що мені потрібно змінити код на найдорожчому рівні дизайну, щоб обробити більш ефективні конструкції. Тож якщо я не '

Ігри - це ще одне поле, схоже на моє. Неважливо, наскільки правильна ваша логічна гра, чи наскільки ретельно і яскраво сконструйовано вашу кодову базу, якщо ваша гра працює зі швидкістю 1 кадр в секунду, як слайд-шоу. У деяких сферах відсутність швидкості може фактично зробити програму непотрібною для користувачів. На відміну від ігор, в таких областях, як променева стрічка, немає "достатньо хорошої" метрики. Користувачі завжди хочуть більшої швидкості, а промислова конкуренція переважно полягає у пошуку швидших рішень. Він ніколи не буде достатньо хорошим, поки не з’явиться в режимі реального часу, в який момент ігри будуть використовувати трасування. І тоді це, мабуть, все ще не буде досить гарним для VFX, оскільки тоді художники можуть захотіти завантажити мільярди полігонів і провести імітацію частинок при самостійному зіткненні серед мільярдів частинок при 30+ FPS.

Тепер, якщо це вам подобається, незважаючи на це, я все одно пишу близько 90% коду на мові сценаріїв (Lua), не турбуючись про продуктивність. Але у мене є незвично велика кількість коду, який насправді потребує прокрутки від мільйонів до мільярдів речей, і коли ти перебираєш мільйони на мільярди речей, ти починаєш помічати епічну різницю між наївним однопоточним кодом, який викликає пропуск кеша з кожною ітерацією проти, скажімо, векторизованим кодом, що працює паралельно з доступом до суміжних блоків, де в кеш-рядок не завантажуються нерелевантні дані.


0

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


0

Відповісти на це питання взагалі неможливо. Більшість програмного забезпечення, яке сьогодні будується, - це внутрішні веб-сайти та програми LOB, і для такого виду програмування ваші міркування цілком правильні. З іншого боку, якщо ви пишете щось на кшталт драйвера пристрою чи ігрового двигуна, оптимізація не є "передчасною"; швидше за все, ваше програмне забезпечення буде працювати в дуже різних системах з різними апаратними обмеженнями. У такому випадку вам слід розробити продуктивність і переконатися, що ви не вибрали неоптимальний алгоритм.


Саме те, що я хотів сказати. Кожна частина програмного забезпечення має свою область застосування, і не слід очікувати, що вона буде вести себе оптимально поза нею. У цьому сенсі передчасна оптимізація є прикладом помилкового перфекціонізму.
К.Штефф

0

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

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

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

Іноді в своєму житті я дізнався, що приріст префікса швидше ...

for (int i = 0; i < MAX; ++i)

... ніж приріст постфікса:

for (int i = 0; i < MAX; i++)

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

Можливо, шукачам ефективності потрібна додаткова мета, крім написання «робочого коду», як-от «робочий і читабельний код», щоб мати орієнтир у великому морі варіантів.


0

чи мені просто пощастило, що мені не доведеться надто переживати про це, чи я поганий програміст?

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

До певної міри ефективність завжди є вимогою. Якщо ви можете вдарити його, не замислюючись про це, ви виправдані, що не думаєте про це.

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

Моє запитання: чому так багато піклується велика кількість програмістів? Це справді проблема для більшості розробників,

Існує велика кількість програмістів, які виправдовуються тим, наскільки вони піклуються. Є велика кількість, яких немає. Поговоримо про тих, кого немає.

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

Кнут мав рацію: передчасна оптимізація - корінь усього зла. Але як тільки це спрацює, що наступний крок? Швидко так? НЕМАЄ! Наступний крок читабельний. Читаною є перший, наступний, середній та останній крок. Багато людей, яких я вважаю, що роблять непотрібні оптимізації продуктивності, кидають читанні під шину.

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

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

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

Крім читабельності - весь світ розробки програмного забезпечення. Про що цей сайт. Деякі не мають поняття, що робити з дизайном. Тому, оскільки вони не можуть вразити дизайном, вони створюють нерозбірливий безлад, тому люди не можуть сказати, що вони не мають поняття. Оскільки ніхто ніколи не виправляє свій код, це повинен бути гарний код правильно?

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

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