Іноді у вас просто є алгоритми, які не можуть бути кращими за лінійний час, на який все ще існує великий попит на продуктивність.
Прикладом є обробка відео, де ви не можете зробити зображення / кадр яскравішим як основний приклад, не переглядаючи кожен піксель (ну, мабуть, ви можете мати якусь ієрархічну структуру, що вказує на властивості, успадковані дітьми, які в кінцевому підсумку опускаються вниз на плитки зображення для листяних вузлів, але тоді ви відкладете більшу вартість прокручування кожного пікселя на рендері, і код, ймовірно, буде важче підтримувати, ніж навіть самий мікрооптимізований фільтр зображення).
Таких випадків у моїй галузі дуже багато. Я схильний робити цикли лінійної складності, які повинні торкатися всього або читати все, ніж ті, які отримують користь від будь-якої складної структури даних або алгоритму. Немає роботи, яку можна пропустити, коли все потрібно торкнутися. Тож у той момент, якщо ви неминуче маєте справу з лінійною складністю, вам доведеться зробити роботу за ітерацією дешевшою та дешевшою.
Тож у моєму випадку найважливішими та найпоширенішими оптимізаціями часто є представлення даних та макети пам'яті, багатопотоковість та SIMD (як правило, у такому порядку, при цьому подання даних є найважливішим, оскільки це впливає на можливість двох останніх). Я не стикаюся з такою кількістю проблем, які вирішуються деревами, хеш-таблицями, алгоритмами сортування та подібними речами. Мій щоденний код більше в дусі: "для кожної речі щось роби".
Звичайно, це ще один випадок поговорити про те, коли необхідні оптимізації (а ще важливіше, коли їх немає), мікро- або алгоритмічні. Але в моєму конкретному випадку, якщо критичний шлях виконання потребує оптимізації, 10-кратне підвищення швидкості часто досягається за допомогою оптимізації на рівні мікрорівнів, таких як багатопотокове читання, SIMD та перестановка макетів пам’яті та шаблонів доступу для поліпшення місцевості посилання. Не так часто мені доводиться, скажімо, замінювати сортування міхурів інтросортом або сортуванням радіації або виявленням зіткнення квадратичної складності з BVH, настільки, щоб знайти гарячі точки, які, скажімо, виграють від розщеплення гарячого / холодного поля.
Тепер у моєму випадку моє поле є настільки критичним для продуктивності (променеві трейсінг, фізичні двигуни тощо), що повільний, але ідеально правильний промінь, який потребує 10 годин для зображення, часто вважається марним або швидшим, ніж швидкий, який є повністю інтерактивним, але виводить найпотворніші зображення, коли промені проникають скрізь через відсутність водонепроникного променя / три перетину. Швидкість, мабуть, є первинною метрикою якості такого програмного забезпечення, імовірно, навіть більше, ніж коректність до певного моменту (оскільки "правильність" - нечітка ідея з прокручуванням, оскільки все наближається до тих пір, поки воно не відбувається збою чи щось подібне). І коли це так, якщо я не думаю про ефективність наперед, я вважаю, що мені потрібно змінити код на найдорожчому рівні дизайну, щоб обробити більш ефективні конструкції. Тож якщо я не '
Ігри - це ще одне поле, схоже на моє. Неважливо, наскільки правильна ваша логічна гра, чи наскільки ретельно і яскраво сконструйовано вашу кодову базу, якщо ваша гра працює зі швидкістю 1 кадр в секунду, як слайд-шоу. У деяких сферах відсутність швидкості може фактично зробити програму непотрібною для користувачів. На відміну від ігор, в таких областях, як променева стрічка, немає "достатньо хорошої" метрики. Користувачі завжди хочуть більшої швидкості, а промислова конкуренція переважно полягає у пошуку швидших рішень. Він ніколи не буде достатньо хорошим, поки не з’явиться в режимі реального часу, в який момент ігри будуть використовувати трасування. І тоді це, мабуть, все ще не буде досить гарним для VFX, оскільки тоді художники можуть захотіти завантажити мільярди полігонів і провести імітацію частинок при самостійному зіткненні серед мільярдів частинок при 30+ FPS.
Тепер, якщо це вам подобається, незважаючи на це, я все одно пишу близько 90% коду на мові сценаріїв (Lua), не турбуючись про продуктивність. Але у мене є незвично велика кількість коду, який насправді потребує прокрутки від мільйонів до мільярдів речей, і коли ти перебираєш мільйони на мільярди речей, ти починаєш помічати епічну різницю між наївним однопоточним кодом, який викликає пропуск кеша з кожною ітерацією проти, скажімо, векторизованим кодом, що працює паралельно з доступом до суміжних блоків, де в кеш-рядок не завантажуються нерелевантні дані.