Чи іноді код з низькою затримкою повинен бути "некрасивим"?


21

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

Чи вважаєте ви, що існує компроміс між написанням «приємного» об'єктно-орієнтованого коду та написанням дуже швидкого коду з низькою затримкою? Наприклад, уникаючи віртуальних функцій у C ++ / накладних поліморфізмів тощо. - переписувати код, який виглядає неприємно, але дуже швидко тощо?

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

Мені було б цікаво почути від людей, які працювали в таких сферах.


1
@ user997112: Близька причина - сама пояснення. У ній сказано: "Ми очікуємо, що відповіді будуть підтверджені фактами, посиланнями чи конкретною експертизою, але це питання, ймовірно, вимагає дискусій, аргументів, опитування чи розширеного обговорення. Це не означає, що вони правильні, але це було близьким" Причина обрана всіма трьома близькими виборцями
Роберт Харві

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

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

1
Вихідний код для диспетчера LMAX не надто негарний. Є деякі частини "до біса з моделлю безпеки Java" (клас Unsafe) та деякі специфічні для апаратних модифікацій (змінені в кеш-рядки змінні), але це дуже читабельний IMO.
Джеймс

5
@ Carson63000, користувач1598390 та хто інший зацікавлений: Якщо питання закінчується закритим , сміливо запитайте про закриття на нашому сайті Meta , мало сенсу обговорювати питання про закриття в коментарях, особливо про закриття, яке не відбулося . Також майте на увазі, що кожне закрите запитання можна повторно відкрити, це ще не кінець світу. За винятком звичайно, якщо майя мали рацію, то в цьому випадку було приємно, що вас усіх знали!
янніс

Відповіді:


31

Чи вважаєте ви, що існує компроміс між написанням «приємного» об'єктно-орієнтованого коду та написанням дуже [sic] коду з низькою затримкою?

Так.

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

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


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

13
Я додам "Міри, не
здогадуйся

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

1
Щодо "передчасної оптимізації" - це все ще застосовується, навіть якщо оптимізований код буде таким же "приємним", як і неоптимізований код. Сенс у тому, щоб не витрачати час на пришвидшення швидкості / того, чого вам не потрібно. Насправді оптимізація не завжди стосується швидкості, і, мабуть, існує таке поняття, як зайва оптимізація для "краси". Ваш код не повинен бути чудовим витвором мистецтва, щоб бути читабельним та реконструйованим.
Стів314

Я другий @ Steve314. Я є продуктовим продуктом і часто знаходжу надмірно складний код, походження якого я можу простежити до якоїсь оптимізації продуктивності. Спрощення цього коду часто виявляє значне підвищення продуктивності. Один з таких прикладів перетворився на покращення продуктивності в 5 разів, коли я спростив це (чисте скорочення тисяч рядків коду). Зрозуміло, що ніхто не витрачав часу, щоб насправді вимірювати, і просто не робила передчасну оптимізацію того, що, на їхню думку , мабуть, повільний код .
Брендон

5

Так, приклад, який я даю, - це не C ++ проти Java, але це збірка проти COBOL, як це я знаю.

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

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

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


3

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

Компроміс пов'язаний із витратами бізнесу. Код, який є більш складним, вимагає більш кваліфікованих програмістів (і програмістів з більш цілеспрямованим набором навичок, таких як архітектура процесора та знання дизайну), потребує більше часу для читання та розуміння коду та виправлення помилок. Вартість бізнесу на розробку та підтримку такого коду може бути в діапазоні 10x - 100x порівняно із звичайно написаним кодом.

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

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

Таким чином, власник бізнесу повинен:

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

Ці компроміси дуже специфічні для обставин.

Їх неможливо оптимально вирішити без участі менеджерів та власників продукції.

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


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

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

Зазвичай SIMD має сильний вплив на читабельність низького рівня, хоча зазвичай не потребує структурних змін вищого рівня (за умови, що API розроблений з урахуванням запобігання вузьким місцем).

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

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

За допомогою функціональної (обчислювальної) декомпозиції алгоритми, які могли бути звичайно записані в лінійній та концептуально чіткій послідовності (рядки коду, які виконуються в тому ж порядку, в якому вони записані), повинні бути розбиті на фрагменти та розподілені на кілька функцій або заняття. (Див. Об'єктивацію алгоритму нижче.) Ця зміна сильно завадить колегам-програмістам, які не знайомі з процесом розробки декомпозиції, який спричинив такий код.

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


Ні, швидкий код не повинен суперечити об'єктно-орієнтованій.

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

Деякі переваги об'єктно-орієнтованого програмування (OOP), такі як інкапсуляція, поліморфізм та композиція, все ще можна отримати від низькорівневого алгоритму-об'єктивації. Це головне обгрунтування використання OOP на цьому рівні.

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


2

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

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


2

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

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

Будь-яка оптимізація, додана для підвищення продуктивності, повинна супроводжуватися відповідним коментарем. Сюди слід віднести твердження про те, що воно було додано як оптимізація, бажано з мірами ефективності до та після.

Я виявив, що правило 80/20 застосовується до оптимізованого коду. Як правило, я не оптимізую нічого, що не займає щонайменше 80% часу. Тоді я прагну (і, як правило, досягаю) збільшення продуктивності в 10 разів. Це покращує продуктивність приблизно в 4 рази. Більшість оптимізацій, які я застосував, не зробили код значно менш "красивим". Ваш пробіг може відрізнятися.


2

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

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

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


Я хотів би запропонувати дві зміни: (1) Є місця, де потрібна швидкість. У тих місцях, я думаю , що це більш доцільно , щоб зробити інтерфейс легко зрозуміти, чому зробити впровадження легко зрозуміти, так як останній може бути набагато складніше. (2) "Код, який виконує нещасні випадки, коли-небудь робить це ...", який я хотів би перефразувати як "Сильний акцент на елегантність та простоту коду рідко є причиною жалюгідної продуктивності. Перший навіть важливіший, якщо часті зміни очікуються, ... »
rwong

Реалізація була поганим вибором слів у розмові OOPish. Я мав на увазі це з точки зору простоти повторного використання та відредагованого. №2, я щойно додав речення, щоб встановити, що 2 - це по суті те, що я робив.
Ерік Reppen

1

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

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


1

Чи вважаєте ви, що існує компроміс між написанням «приємного» об'єктно-орієнтованого коду та написанням дуже швидкого коду з низькою затримкою? Наприклад, уникаючи віртуальних функцій у C ++ / накладних поліморфізмів тощо. - переписувати код, який виглядає неприємно, але дуже швидко тощо?

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

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

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

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

Проектування для продуктивності

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

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

Грубіший дизайн інтерфейсу

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

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

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

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

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

Басейн пам'яті

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

Ідея точно така сама - підштовхувати дорогі речі (розподіляти шматок пам’яті проти розподільника загального призначення, наприклад) на більш грубий і грубіший рівень. Пул пам'яті призначений для масової роботи з пам'яттю .

Тип Системна роздільна пам'ять

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

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

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

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

У таких мовах, як Java, може бути корисним використовувати більше масивів простих старих типів даних, коли це можливо для вузьких місць (областей, оброблених у вузьких петлях), таких як масив int(але все ще знаходиться за об'ємним інтерфейсом високого рівня) замість, скажімо , об'єктів, ArrayListвизначених користувачем Integer. Це дозволяє уникнути поділу пам'яті, яка зазвичай супроводжує останню. У C ++ нам не доведеться так сильно погіршувати структуру, якщо наші схеми розподілу пам’яті ефективні, оскільки визначені користувачем типи можуть постійно розподілятися там і навіть у контексті загального контейнера.

З'єднання пам'яті разом

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

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

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

Некрасивий

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

Небезпечний

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

Краса

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

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

TL; DR

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


0

Щоб не бути іншим, але ось що я роблю:

  1. Напишіть її чистою та ретельною.

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

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

Так чи є компроміс? Я не думаю, що так.


0

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


0

Що важливо для кінцевого користувача?

  • Продуктивність
  • Особливості / функціональність
  • Дизайн

Випадок 1: Оптимізований неправильний код

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

Випадок 2: Неоптимізований хороший код

  • Простота обслуговування
  • Поганий досвід користувача

Рішення?

Легко, оптимізуйте критичні фрагменти коду

наприклад:

Програма, що складається з 5 методів , 3 з них - для управління даними, 1 - для читання дисків, інша - для запису на диск

Ці 3 методи управління даними використовують два методи вводу-виводу та залежать від них

Ми б оптимізували методи вводу / виводу.

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

Це означає, що ми отримуємо хороший код та керований дизайн програми, зберігаючи її швидко, оптимізуючи певні частини коду

Я думаю..

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

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