Я хотів би запитати людей, які мають досвід роботи з системами, масштаб Visual Studio: що це робить їх повільними? Чи потрібні шари на шари абстракцій, щоб зберегти кодову базу в межах можливостей людського розуміння? Це чиста кількість коду, яку потрібно пропустити? Чи є сучасна тенденція до підходів програміста, що заощаджує час, на (розумно величезний) рахунок у відділі циклів годин / використання пам'яті?
Я думаю, що ти здогадався про їхню кількість, але я хотів би запропонувати те, що я вважаю найбільшим фактором, працюючи над досить великою базою коду (не впевнений, чи він такий великий, як Visual Studio - був у мільйонах рядків коду категорія і близько тисячі плагінів) протягом приблизно 10 років і спостерігаються явища.
Це також трохи менш суперечливо, оскільки він не входить в API чи мовні функції чи щось подібне. Вони стосуються "витрат", які можуть породжувати дебати, а не "витрати", і я хочу зосередитись на "витратах".
Вільна координація та спадщина
Що я зауважив, це те, що слабка координація та тривалий спадщина, як правило, призводять до великої кількості накопичених відходів.
Наприклад, у цій кодовій базі я знайшов близько ста структур прискорення, багато з яких були зайвими.
Нам хотілося б дерево KD для прискорення роботи одного двигуна фізики, інше для нового двигуна фізики, який часто працював паралельно старому, ми мали б десятки реалізацій octrees для різних сітчастих алгоритмів, інше дерево KD для візуалізації , збирання і т. д. і т. д. Це все великі об'ємні дерева структури, які використовуються для прискорення пошуку. Кожен окремий може зайняти сотні мегабайт до гігабайт пам'яті за дуже середній розмір входу. Вони не завжди були примірниками та використовувались весь час, але в будь-який момент часу 4 чи 5 з них могли бути в пам'яті одночасно.
Тепер усі вони зберігали такі самі дані, щоб прискорити їх пошук. Ви можете уявити це як аналогічну стару базу даних, яка зберігає всі її поля у 20 різних зайвих картах / словниках / B + деревах одразу, впорядкованих однаково за допомогою одних і тих же клавіш, і здійснює пошук у них весь час. Тепер ми займаємо 20 разів більше пам'яті та обробку.
Крім того, через надмірність, мало часу на оптимізацію будь-якого з них із ціною технічного обслуговування, яка поставляється разом із цим, і навіть якби ми це зробили, це матиме лише 5% ефекту, який він ідеально би.
Що викликає це явище? Послаблена координація була причиною номер один, яку я бачив. Багато членів команди часто працюють у своїх ізольованих екосистемах, розробляючи або використовуючи структури даних сторонніх організацій, але не використовують ті самі структури, які використовували інші члени команди, навіть якщо вони були прямо відвертими дублюючими дублікатами.
Що зумовлює збереження цього явища? Спадщина та сумісність була причиною номер один, яку я бачив. Оскільки ми вже сплатили витрати на реалізацію цих структур даних і велика кількість коду залежала від цих рішень, часто було занадто ризиковано намагатися консолідувати їх до меншої кількості даних даних. Незважаючи на те, що багато хто з цих структур концептуально були надлишковими, вони не завжди були близькими до однакових у своїх інтерфейсних конструкціях. Таким чином, їх заміна була б великою, ризикованою зміною на відміну від того, щоб просто дозволяти їм споживати пам'ять та час обробки.
Ефективність пам'яті
Зазвичай використання пам’яті та швидкість, як правило, пов'язані щонайменше на рівні масового використання. Часто ви можете помітити повільне програмне забезпечення, як він підкручує пам'ять. Це не завжди правда, що більша кількість пам'яті призводить до уповільнення, оскільки важливе значення має "гаряча" пам'ять (яка пам'ять постійно використовується - якщо програма використовує завантаження пам'яті, але лише 1 мегабайт її використовується весь час, то це не така вже й велика швидкість).
Таким чином, ви можете помітити потенційних свиней на основі використання пам'яті багато часу. Якщо додаток займає десятки до сотень мегабайт пам'яті при запуску, це, мабуть, не буде дуже ефективним. Десятки мегабайт можуть здатися невеликими, коли у нас сьогодні є гігабайти DRAM, але найбільший і найповільніший кеш процесора все ще знаходиться в діапазоні шалених мегабайт, а найшвидший - все ще в діапазоні кілобайт. Як результат, програма, яка використовує 20 мегабайт просто для запуску і нічого не робить, насправді все ще використовує досить "багато" пам'яті з точки зору кешу апаратного процесора, особливо якщо всі 20 мегабайт цієї пам'яті будуть доступні неодноразово і часто, коли програма працює.
Рішення
Для мене рішення - шукати більш скоординовані, менші команди для створення продуктів, які зможуть відслідковувати свої "витрати" і уникати "купівлі" одних і тих же предметів знову і знову.
Вартість
Я занурюся в більш суперечливий "витратний" бік лише підлітковий біт із явищами "витрачання", які я спостерігав. Якщо мова в кінцевому підсумку позначає неминучий цінник для об'єкта (наприклад, який забезпечує відображення часу виконання і не може примусити безперервного розподілу для ряду об'єктів), цей цінник дорогий лише в контексті дуже зернистого елемента, наприклад одинарний Pixel
або Boolean
.
Але я бачу багато вихідного коду для програм, які справляються з великим навантаженням (наприклад, спілкування з сотнями тисяч до мільйонів Pixel
або Boolean
екземплярів), оплачуючи ці витрати на такому детальному рівні.
Об'єктно-орієнтоване програмування це може дещо посилити. Але це не винні "об'єкти" самі по собі або навіть OOP з вини, це просто те, що такі витрати оплачуються на такому детальному рівні підліткового елемента, який збирається придумати мільйонами.
Тож це і інші явища "витрат" та "витрат", які я спостерігаю. Вартість - копійки, але копійки складаються, якщо ми купуємо мільйон банок соди окремо, а не домовляємось з виробником щодо масової закупівлі.
Тут для мене рішення - «оптова» покупка. Об'єкти є прекрасними навіть на мовах, які мають певну ціну копій за кожну, за умови, що ця вартість не виплачується індивідуально мільйон разів за аналогічний еквівалент банки з содою.
Передчасна оптимізація
Мені ніколи не сподобалося вживане тут формулювання Knuth, оскільки "передчасна оптимізація" рідко змушує реальні виробничі програми йти швидше. Деякі трактують це як "оптимізацію рано", коли Кнут мав на увазі більше як "оптимізацію без належних знань / досвіду, щоб знати її справжній вплив на програмне забезпечення". У будь-якому разі, практичний ефект справжньої передчасної оптимізації часто робить програмне забезпечення повільнішим , оскільки деградація ремонтопридатності означає, що мало часу для оптимізації критичних шляхів, які насправді мають значення .
Це остаточне явище, яке я спостерігав, коли розробники, домагаючись заощаджувати копійки на придбання єдиної банки соди, ніколи більше не купувались, або, ще гірше, будинок, витрачали весь свій час, притискаючи копійки (або ще гірше, уявні копійки з не розуміючи їх компілятора чи архітектури обладнання), коли мільярди доларів були марно витрачені в іншому місці.
Час дуже обмежений, тому спроби оптимізувати абсолюти, не маючи належної контекстної інформації, часто позбавляють нас можливості оптимізувати місця, які справді мають значення, і, таким чином, з точки зору практичного ефекту, я б сказав, що "передчасна оптимізація робить програмне забезпечення набагато повільнішим. "
Проблема полягає в тому, що є типи розробників, які приймуть те, що я писав вище про об'єкти, і спробують встановити стандарт кодування, який забороняє об'єктно-орієнтоване програмування або щось божевільне подібного типу. Ефективна оптимізація - це ефективне визначення пріоритетів, і це абсолютно марно, якщо ми потопаємо в морі проблем з технічним обслуговуванням.