Стратегії оптимізації ефективності останньої інстанції [закрито]


609

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

Припустимо:

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

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

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

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

Відповіді:


427

Гаразд, ви визначаєте проблему в тому, де, здавалося б, не так багато можливостей для вдосконалення. На моєму досвіді це досить рідко. Я спробував пояснити це в статті доктора Доббса в листопаді 1993 року, починаючи з звичайно добре розробленої нетривіальної програми без очевидних відходів і приймаючи її через низку оптимізацій, поки час її настінного годинника не скоротився з 48 секунд до 1,1 секунди, а розмір вихідного коду було зменшено в 4 рази. Мій діагностичний інструмент був таким . Послідовність змін була така:

  • Першою виявленою проблемою було використання кластерів списків (тепер їх називають "ітератори" та "класи контейнерів"), що займають більше половини часу. Вони були замінені досить простим кодом, скоротивши час до 20 секунд.

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

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

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

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

  • Це оновлення зроблено, зменшуючи вихідний код в 4 рази, а час скорочується до 10 секунд.

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

  • Більш діагноз показує, що він витрачає час на керування чергою. Накладки зменшують час до 7 секунд.

  • Зараз великим зайняттям часу є діагностичний друк, який я робив. Промийте це - 4 секунди.

  • Зараз найбільші споживачі часу - це дзвінки на безіменний та безкоштовний . Переробити предмети - 2,6 секунди.

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

Загальний коефіцієнт швидкості: 43,6

Зараз жодна дві програми не схожі, але в неіграшному програмному забезпеченні я завжди бачив такий прогрес. Спочатку ви отримуєте легкі речі, а потім більш складні, поки не дістанетесь до точки зменшення віддачі. Тоді зрозуміння, яке ви отримаєте, цілком може призвести до зміни дизайну, починаючи новий раунд прискорень, доки ви знову не потрапите на зменшувані прибутки. Тепер це точка , в якій вона може мати сенс засумніватися в тому , ++iчи i++або for(;;)чи while(1)швидше: види питань , які я бачу так часто на переповнення стека.

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

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

ДОДАТИ: jerryjvl попросив кілька прикладів. Ось перша проблема. Він складається з невеликої кількості окремих рядків коду, разом займаючи половину часу:

 /* IF ALL TASKS DONE, SEND ITC_ACKOP, AND DELETE OP */
if (ptop->current_task >= ILST_LENGTH(ptop->tasklist){
. . .
/* FOR EACH OPERATION REQUEST */
for ( ptop = ILST_FIRST(oplist); ptop != NULL; ptop = ILST_NEXT(oplist, ptop)){
. . .
/* GET CURRENT TASK */
ptask = ILST_NTH(ptop->tasklist, ptop->current_task)

Вони використовували кластер списку ILST (подібно до класу списку). Вони реалізовані звичайним способом, "приховування інформації" означає, що користувачі класу не повинні були дбати про те, як вони були реалізовані. Коли ці рядки були написані (приблизно з 800 рядків коду), думка не замислювалася над тим, що вони можуть бути «вузьким місцем» (я ненавиджу це слово). Вони просто рекомендований спосіб робити речі. Неважко сказати заднім числом, що цього слід було уникати, але, на моєму досвіді, всі проблеми з виконанням роботи є такими. Загалом, добре намагатися уникати проблем із продуктивністю. Ще краще знайти та виправити створені, хоча їх "слід було уникати" (заднім числом).

Ось друга проблема, у двох окремих рядках:

 /* ADD TASK TO TASK LIST */
ILST_APPEND(ptop->tasklist, ptask)
. . .
/* ADD TRANSACTION TO TRANSACTION QUEUE */
ILST_APPEND(trnque, ptrn)

Це списки складання, додаючи елементи до їх кінців. (Виправлення полягало в тому, щоб збирати елементи в масивах та створювати списки всі відразу.) Цікавим є те, що ці висловлювання коштували лише (тобто були у стеку викликів) 3/48 початкового часу, тому їх не було в фактично велика проблема на початку . Однак після усунення першої проблеми вони коштували 3/20 часу і тому тепер були «більшою рибою». Загалом, так воно і йде.

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

ДОВІДКА ДОПОМОГА: Вихідний код, як оригінальний, так і перероблений, можна знайти на веб-сайті www.ddj.com за 1993 рік у файлі 9311.zip, файлах slug.asc та slug.zip.

EDIT 2011/11/26: Зараз існує проект SourceForge, що містить вихідний код у Visual C ++ та опис того, як його було налаштовано. Він проходить лише першу половину описаного вище сценарію, і він не дотримується абсолютно тієї ж послідовності, але все ж отримує прискорення на 2-3 порядку.


3
Я хотів би прочитати деякі деталі кроків, які ви окреслили вище. Чи можна включити деякі фрагменти оптимізації для аромату? (не роблячи посаду занадто довгою?)
jerryjvl

8
... Я також написав книгу, яка зараз не надрукується, тому вона виходить за смішну ціну на Amazon - "Створення кращих застосунків" ISBN 0442017405. По суті той самий матеріал є в першому розділі.
Майк Данлаве

3
@Mike Dunlavey, я б запропонував сказати Google, що ви її вже відсканували. Вони, мабуть, вже мають угоду з тим, хто купив вашого видавця.
Thorbjørn Ravn Andersen

19
@ Thorbjørn: Щоб продовжити роботу, я підключився до GoogleBooks, заповнив усі форми та надіслав їм копію. Мені повернувся електронний лист із запитом, чи дійсно я володію авторськими правами. Видавець Van Nostrand Reinhold, якого купив International Thompson, який купив Reuters, і коли я намагаюся зателефонувати їм або надіслати електронною поштою, це як чорна діра. Так це в кінцівці - я ще не мав енергії, щоб справді її гнати.
Майк Данлаве

5
Посилання на Google Книги: books.google.dk/books?id=8A43E1UFs_YC
Thorbjørn Ravn Andersen

188

Пропозиції:

  • Попередньо обчисліть, а не перераховуйте : будь-які цикли або повторні виклики, що містять обчислення, що мають відносно обмежений діапазон входів, розгляньте можливість пошуку (масиву чи словника), який містить результат цього обчислення для всіх значень у допустимому діапазоні входи. Потім використовуйте простий пошук всередині алгоритму.
    Нижній бік : якщо фактично використовуються кілька попередньо обчислених значень, це може погіршити ситуацію, також пошук може зайняти значну пам’ять.
  • Не використовуйте бібліотечні методи : більшість бібліотек потрібно писати для правильної роботи в широкому діапазоні сценаріїв, а також виконувати нульові перевірки параметрів тощо. Повторно реалізуючи метод, ви зможете позбавити багато логіки, що не застосовується в тій обставині, якою ви користуєтесь.
    Внизу : написання додаткового коду означає більше площі поверхні для помилок.
  • Використовуйте бібліотечні методи : щоб суперечити собі, мовні бібліотеки пишуть люди, які набагато розумніші за вас чи мене; шанси це зробити це краще і швидше. Не реалізуйте це самостійно, якщо ви дійсно не зможете зробити це швидше (тобто: завжди міряйте!)
  • Чит : у деяких випадках, хоча точний розрахунок може існувати для вашої проблеми, можливо, вам не знадобиться "точний", іноді наближення може бути "досить хорошим" і набагато швидшим в угоді. Запитайте себе, чи не має значення, якщо відповідь на 1%? 5%? навіть 10%?
    Вниз : Ну ... відповідь не буде точною.

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

37
Обман часто може бути виграшним. У мене був процес корекції кольорів, що в основі лежав 3-векторний пунктир з матрицею 3x3. У процесорі було встановлено матричне множення в апаратному забезпеченні, яке виключало деякі перехресні терміни і швидко реалізовувалося порівняно з усіма іншими способами, але підтримувала лише матриці 4x4 та 4 вектори поплавків. Зміна коду для переміщення зайвого порожнього слота та перетворення обчислення в плаваючу точку з фіксованої точки дозволяють отримати дещо менш точний, але набагато швидший результат.
RBerteig

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

6
@RBerteig: просто "достатньо правильно" - це можливість для оптимізації, яку більшість людей сумує за моїм досвідом.
Мартін Томпсон,

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

164

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

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

Кілька прикладів:

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

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


27
Штрих, що прискорюється в кінці, може сприйматися як швидший, ніж абсолютно точний. У «Переосмисленні смуги прогресу» (2007) Гаррісон, Аменто, Кузнєцов та Белл перевіряють кілька типів барів для групи користувачів, а також обговорюють деякі способи переставити операції, щоб прогрес сприймався як швидший.
Еміль Вікстрьом

9
naxa, більшість барів прогресу підроблені, тому що прогнозувати багаторічно різні етапи потоку в один відсоток важко або іноді неможливо. Подивіться на всі ті бари, які застрягли на 99% :-(
Еміль Вікстрьом

138

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

  • Кеш пропускає . Кеш даних є першим джерелом кіосків у більшості програм. Покращити частоту показів кешу, реорганізувавши структури даних, що порушують правопорушення, щоб мати кращу локальність; упакуйте структури та числові типи вниз для усунення марних байтів (і, отже, витрачених даних кешу); попередньо виберіть дані, де це можливо, щоб зменшити кількість стоянок.
  • Навантажувачі-магазини . Припущення компілятора про псевдонім вказівника та випадки, коли дані переміщуються між відключеними наборами регістрів через пам'ять, можуть спричинити певну патологічну поведінку, яка змушує очистити весь конвеєр процесора під час завантаження. Знайдіть місця, де поплавці, вектори та вставки кидаються один одному та ліквідуйте їх. Використовуйте __restrictвільно, щоб пообіцяти компілятору про згладжування.
  • Операції з мікрокодуваннями . Більшість процесорів мають деякі операції, які неможливо провести конвеєрним шляхом, але натомість виконують крихітну підпрограму, що зберігається в ПЗУ. Приклади PowerPC - це ціле множення, ділення та перехід на змінну кількість. Проблема полягає в тому, що під час виконання цієї операції весь трубопровід зупиняється мертвим. Спробуйте виключити використання цих операцій або, принаймні, розбити їх на складові конвеєрні трубопроводи, щоб ви могли отримати перевагу надшвидкої розсилки на будь-яку іншу частину вашої програми.
  • Відділення mispredicts . Ці занадто порожні трубопроводи. Знайдіть випадки, коли центральний процесор витрачає багато часу на поповнення труби після гілки, і використовуйте підказку гілки, якщо вона доступна, щоб її частіше прогнозувати правильно. Або ще краще, замініть гілки на умовні рухи, коли це можливо, особливо після операцій з плаваючою точкою, оскільки їх труба зазвичай глибша і зчитування прапорів стану після fcmp може спричинити застій.
  • Послідовні опси з плаваючою комою . Зробіть ці SIMD.

І ще одне, що я люблю робити:

  • Встановіть ваш компілятор для виведення списків складання і подивіться, що він видає для функцій точки доступу у вашому коді. Усі ті розумні оптимізації, які "хороший компілятор повинен мати можливість зробити для вас автоматично"? Ймовірно, ваш фактичний компілятор не виконує їх. Я бачив, як GCC випромінює код WTF.

8
Я в основному використовую Intel VTune та PIX. Поняття не маю, чи зможуть вони адаптуватися до C #, але насправді після того, як ви отримаєте цей шар абстрагування JIT, більшість цих оптимізацій є поза вашим досяжністю, за винятком покращення місцевості кешу та, можливо, уникнення деяких гілок.
Crashworks

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

5
Я думаю, що багато людей, в тому числі і я, були б зацікавлені у цій "збірці wtf", виробленій gcc. Ваше звучить як дуже цікава робота :)
BlueRaja - Danny Pflughoeft

1
Examples on the PowerPC ...<- Тобто, деякі реалізації PowerPC. PowerPC - це ISA, а не процесор.
Біллі ONeal

1
@BillyONeal Навіть на сучасному обладнання x86, imul може зупинити конвеєр; див. "Посібник з оптимізації архітектури Intel® 64 та IA-32", § 13.3.2.3: "Інструкція множення цілих літрів виконує кілька циклів. Вони прокладені так, що інструкція з множенням на ціле число та інша інструкція з тривалим запізненням можуть просуватися вперед. Фаза виконання. Однак інструкції з множення цілих чисел блокують видачу інших цілих циклів одноциклу через вимогу програмного замовлення. " Ось чому зазвичай краще використовувати розміщені у розмірі масиви і lea.
Crashworks

78

Киньте на це більше обладнання!


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

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

19
@Crashworks або, з цього приводу, вбудована система. Коли остання функція нарешті з'явилася, і перша партія плати вже закручена, це не момент, коли можна виявити, що вам слід було б скористатися швидшим процесором в першу чергу ...
RBerteig,

71
Мені одного разу довелося налагоджувати програму, яка мала величезну протікання пам'яті - її розмір VM зростав приблизно на 1 Мбіт на годину. Колега жартував, що все, що мені потрібно було, - це додавати пам'ять з постійною швидкістю . :)
j_random_hacker

9
Більше обладнання: ах, посередній життєвий шлях розробника. Я не знаю, скільки разів я чув "додайте ще одну машину і подвоюйте ємність!"
Олоф Форшелл

58

Більше пропозицій:

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

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

  • Затримка вводу / виводу : Не виписуйте свої результати, поки не закінчиться розрахунок, збережіть їх у структурі даних, а потім скидайте їх за один крок наприкінці, коли буде виконана важка робота.

  • Різьбовий введення / виведення : Для тих, хто досить сміливий, поєднайте «I / O вперед» або «Затримка вводу / виводу» з фактичним розрахунком, перемістивши завантаження в паралельну нитку, так що під час завантаження більшої кількості даних ви можете працювати на обчислення даних, які у вас уже є, або під час обчислення наступної партії даних ви можете одночасно виписати результати з останньої партії.


3
Зауважте, що "переміщення IO в паралельний потік" слід робити як асинхронний IO на багатьох платформах (наприклад, Windows NT).
Біллі ONeal

2
Введення / виведення - це дійсно критичний момент, оскільки він повільний і має величезні затримки, і ви можете отримати швидше з цією порадою, але це все ще є принципово недоліком: бали - це затримка (яку потрібно приховати) і накладення системного дзвінка ( що має бути зменшено за рахунок зменшення кількості викликів вводу / виводу). Найкраща порада: використовувати mmap()для введення даних, виконувати відповідні madvise()дзвінки та використовувати aio_write()для запису великих фрагментів виходу (= декілька MiB).
cmaster - відновити моніку

1
Цей останній варіант досить легко реалізувати на Java, особливо. Це дало великі підвищення продуктивності для написаних нами додатків. Ще один важливий момент (більш ніж переміщення вводу / виводу вперед) - це зробити його СЕКВЕНТАЛЬНИМ та великоблочним введенням / виводом. Багато невеликих читань набагато дорожче, ніж 1 велике, через час пошуку диска.
BobMcGee

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

48

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

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

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

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

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

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

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

Ніколи не ставити цикл будь-якого типу в тригер!

У більшості баз даних є спосіб перевірити, як буде виконуватися запит. У Microsoft SQL Server це називається планом виконання. Спершу перегляньте ті, щоб побачити, де лежать проблемні зони.

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

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

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


29

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

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

У багатьох коментарях уже згадується кеш-код. Є щонайменше два різних смаку цього:

  • Слід уникати затримок пам'яті.
  • Зниження тиску в шині пам'яті (пропускна здатність).

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

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

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


25
  • На якому апаратному забезпеченні ви працюєте? Чи можете ви використовувати оптимізацію для платформи (наприклад, векторизацію)?
  • Чи можете ви отримати кращий компілятор? Наприклад, перехід від GCC до Intel?
  • Чи можете ви зробити алгоритм роботи паралельно?
  • Чи можете ви зменшити пропуски кешу, реорганізувавши дані?
  • Чи можете ви відключити твердження?
  • Мікрооптимізація для вашого компілятора та платформи. У стилі "в" if / else "спочатку поставте найпоширеніший вислів"

4
Потрібно "перейти з GCC на LLVM" :)
Zifre

4
Чи можете ви зробити алгоритм роботи паралельно? - також застосовується зворотна сторона
Justin

4
Правда, зменшення кількості ниток може бути не менш хорошою оптимізацією
Йохан Котлінський

re: мікрооптимізація: якщо ви перевіряєте вихід ASM компілятора, ви можете часто налаштовувати джерело, щоб перенести його на отримання кращої ASM. Дивіться, чому цей код C ++ швидше, ніж моя рукописна збірка для тестування гіпотези Collatz? для отримання додаткової інформації про допомогу або побиття компілятора на сучасних x86.
Пітер Кордес

17

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

З’ясуйте, що спочатку займає найбільше часу, і зрозумійте, чому.

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

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

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

ВПЛ, асудмову.


16

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

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

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


15
  • Вбудовані процедури (усунення виклику / повернення та натискання параметрів)
  • Спробуйте усунути тести / комутатори за допомогою перегляду таблиць (якщо вони швидші)
  • Розкрутіть петлі (пристрій Даффа) до місця, де вони просто поміщаються в кеш-пам'яті процесора
  • Локалізуйте доступ до пам'яті, щоб не дути кеш
  • Локалізуйте пов'язані обчислення, якщо оптимізатор цього ще не робить
  • Усуньте інваріанти циклу, якщо оптимізатор цього ще не робить

2
Пристрій IIRC Даффа дуже рідко швидше. Тільки тоді, коли оп дуже короткий (на зразок одного невеликого математичного виразу)
BCS

12
  • Коли ви доходите до того, що ви використовуєте ефективні алгоритми, виникає питання, що вам потрібно більше швидкості чи пам'яті . Використовуйте кешування для "оплати" в пам'яті для більшої швидкості або використовуйте розрахунки, щоб зменшити слід пам'яті.
  • Якщо можливо (і більш економічно) кинути апаратне забезпечення на проблему - швидший процесор, більше пам’яті чи HD може вирішити проблему швидше, ніж намагатися її кодувати.
  • Використовуйте паралелізацію, якщо це можливо - запустіть частину коду на декількох потоках .
  • Скористайтеся правильним інструментом для роботи . деякі мови програмування створюють більш ефективний код, використовуючи керований код (тобто Java / .NET), прискорюючи розробку, але рідні мови програмування створюють швидший запущений код.
  • Мікро оптимізація . Тільки застосовні, ви можете використовувати оптимізовану збірку для прискорення невеликих фрагментів коду, використання оптимізацій SSE / вектора в потрібних місцях може значно підвищити продуктивність.

12

Розділяй і володарюй

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


9
+1 за звук мухоловки "присмак", який я почув, читаючи останнє речення.
Брайан Боттчер

11

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

  • ... якщо це пам'ять - знайдіть одну з книг, написану давно Данутом, одну із серії «Мистецтво комп’ютерного програмування». Швидше за все, це стосується сортування та пошуку - якщо моя пам’ять помилкова, то вам доведеться дізнатися, у якому він розповідає про те, як боротися з повільним зберіганням даних. Подумки перетворюйте його вичавлювання до останніх кількох відсотків так? Якщо насправді мало, ви, швидше за все, виграєте. пам'ять / стрічки пару у вашу пару кешу / основної пам’яті (або в пару кешу L1 / L2) відповідно. Вивчіть усі описи, які він описує - якщо ви не знайдете щось, що вирішує вашу проблему, то наймайте професійного комп'ютерного фахівця для проведення професійного дослідження. Якщо у вашій пам'яті випадково виникає FFT (кеш не вистачає на біт-обернених індексах, коли ви робите метелики radix-2), тоді не наймайте науковця - натомість оптимізуйте вручну проходить один за одним, поки ви не '

  • ... якщо це процесор - переключіться на мову складання. Вивчення специфікації процесора - для чого потрібні кліщі , VLIW, SIMD. Функціональні дзвінки, швидше за все, можуть бути зміненими галочками. Вивчіть перетворення циклу - конвеєр, розкрутка. Множення та ділення можуть бути замінені / інтерпольовані з переміщенням бітів (множення на малі цілі числа може бути замінено на додавання). Спробуйте хитрощі з більш короткими даними - якщо вам пощастить, одна інструкція з 64 бітами може виявитися заміною двома на 32 або навіть 4 на 16 або 8 на 8 біт. Спробуйте також довшедані - наприклад, ваші обчислення з плаваючою можливістю виявляться повільнішими, ніж подвійні в конкретному процесорі. Якщо у вас є тригонометричні речі, поправте їх за допомогою попередньо обчислених таблиць; також майте на увазі, що синус малої величини може бути замінений цим значенням, якщо втрата точності знаходиться в допустимих межах.

  • ... якщо це мережа - подумайте про стиснення даних, які ви передаєте через них. Замініть передачу XML двійковою. Вивчіть протоколи. Спробуйте UDP замість TCP, якщо ви зможете якось впоратися із втратою даних.

  • ... якщо це база даних, добре, перейдіть на будь-який форум баз даних і попросіть поради. Сітка даних в пам'яті, оптимізація плану запитів тощо, тощо, тощо.

HTH :)


9

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

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


8

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

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

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


8

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

  • Захід : Почніть з розуміння основної потужності та топології мережі. Поговоріть з відповідними мережевими людьми в бізнесі та скористайтеся основними інструментами, такими як ping та traceroute, щоб встановити (як мінімум) затримку в мережі для кожного клієнта протягом типових періодів роботи. Далі проводите точні вимірювання часу конкретних функцій кінцевого користувача, які відображають проблемні симптоми. Запишіть усі ці вимірювання разом з їх місцезнаходженням, датами та часом. Розгляньте можливість побудови функціонування кінцевого користувача "тестування роботи мережі" у своєму клієнтському застосуванні, щоб ваші користувачі влади могли брати участь у процесі вдосконалення; Надання їм таких можливостей може мати величезний психологічний вплив, коли ви маєте справу з користувачами, розчарованими погано працюючою системою.

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

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

  • Паралельність : шукайте послідовні транзакції, які логічно не потрібно видавати суворо послідовно, і переробляйте систему, щоб видавати їх паралельно. Я розглядав один випадок, коли запит від кінця до кінця мав вбудовану мережеву затримку ~ 2s, що не було проблемою для однієї транзакції, але коли потрібно 6 послідовних 2-х турових поїздок, перш ніж користувач відновив контроль над клієнтською програмою , це стало величезним джерелом розчарування. Виявлення, що ці трансакції насправді були незалежними, дозволило їх виконувати паралельно, зменшивши затримку кінцевого споживача до дуже близьких до вартості разової поїздки.

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

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

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

На етапах, описаних вище, я зосереджуюсь на процесі оптимізації, пов’язаного із додатком, але, звичайно, ви повинні переконатися, що основна мережа налаштована найбільш ефективно, щоб підтримувати і ваш додаток. Залучіть фахівців з мереж у бізнесі та визначте, чи здатні вони застосувати покращення потужностей, QoS, стиснення мережі чи інші методи вирішення проблеми. Зазвичай вони не розуміють потреб вашої програми, тому важливо, щоб ви були готові (після кроку аналізу) обговорити це з ними, а також скласти бізнес-випадок за будь-які витрати, які ви будете вимагати від них. . Я стикався з випадками, коли помилкова конфігурація мережі спричиняла передачу даних програм через повільну супутникову лінію, а не наземну лінію, просто тому, що він використовував порт TCP, який не був «добре відомий» фахівцями з мереж; очевидно, виправлення такої проблеми може мати драматичний вплив на продуктивність, без необхідності зміни програмного коду чи конфігурації.


7

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


7

Останні кілька% - це дуже важливий процесор і додаток ....

  • архітектури кеша відрізняються, деякі мікросхеми мають чіп оперативної пам’яті, яку можна безпосередньо відобразити, ARM (іноді) має векторну одиницю, SH4 - корисний матричний опкод. Є GPU - можливо, шейдер - це шлях. TMS320 's дуже чутливі до гілок всередині циклів (тому окремі петлі та переміщуйте умови зовні, якщо можливо).

Список продовжується .... Але такі речі справді є останнім заходом ...

Створіть для x86 та запустіть Valgrind / Cachegrind проти коду для правильного профілювання продуктивності. Або CCStudio компанії Texas Instruments має приємний профайл . Тоді ви дійсно будете знати, куди зосередитись ...


7

Did you know that a CAT6 cable is capable of 10x better shielding off extrenal inteferences than a default Cat5e UTP cable?

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


7

Не настільки глибокі чи складні, як попередні відповіді, але ось що: (це більше початковий / проміжний рівень)

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

4
Про циклічення назад: так, порівняння для кінця циклу буде швидшим. Як правило, ви використовуєте змінну для індексації в пам'яті, а доступ до неї повернено може бути контрпродуктивним через часті пропуски кешу (немає попереднього вибору).
Андреас Рейфф

1
AFAIK, в більшості випадків, будь-який розумний оптимізатор буде чудово виконувати цикли, без програміста явно запускатись у зворотному напрямку. Або оптимізатор поверне цикл сам, або він має такий же хороший спосіб. Я відзначив однаковий вихід ASM для (правда, відносно простих) циклів, написаних як висхідними, так і максимальними та низхідними проти 0. Звичайно, мої дні Z80 мають звичку рефлекторно писати зворотні петлі, але я підозрюю, що згадувати це для новачків, як правило, червона оселедець / передчасна оптимізація, коли читати код та вивчати важливіші практики повинні бути пріоритетом.
підкреслюй_d

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

5

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

Краще місце кешування, розгортання циклу, Спробуйте усунути довгі ланцюги залежностей, щоб отримати кращий паралелізм на рівні інструкцій. Віддайте перевагу умовному переміщенню над гілками, коли це можливо. Використовуйте інструкції SIMD, коли це можливо.

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

Ну, це, і "Показати код на SO та запитати поради щодо оптимізації для цього конкретного фрагмента коду".


5

Якщо краще апаратне забезпечення - це варіант, тоді, безумовно, йдіть на це. Інакше

  • Перевірте, чи використовуєте ви найкращі параметри компілятора та лінкера.
  • Якщо звичайна точка доступу в іншій бібліотеці є частою, що телефонує, розгляньте можливість переміщення або клонування її до модуля виклику. Усуває частину накладних викликів та може покращити звернення до кешу (див. Як AIX статично посилає strcpy () на окремо пов'язані спільні об'єкти). Це, звичайно, також може зменшити кількість показів кешу, тому одна міра.
  • Перевірте, чи є можливість використання спеціалізованої версії розпорядку гарячої точки. Downside - це більше, ніж одна версія.
  • Подивіться на асемблера. Якщо ви думаєте, що це може бути краще, подумайте, чому компілятор цього не з'ясував, і як ви могли допомогти компілятору.
  • Поміркуйте: ви справді використовуєте найкращий алгоритм? Це найкращий алгоритм для вашого розміру введення?

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

5

Шлях google - це одна з опцій "Кешуйте його. Коли це можливо, не торкайтеся диска"


5

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

Дізнайтеся, де витрачається час Дізнайтеся, що саме займає час. Це файл IO? Це час процесора? Це мережа? Це база даних? Оптимізувати IO марно, якщо це не вузьке місце.

Знайте своє середовище Знання місця оптимізації зазвичай залежить від середовища розробки. Наприклад, у VB6 передача посилань повільніше, ніж передача за значенням, але у C та C ++ посилання значно швидше. У C доцільно спробувати щось і зробити щось інше, якщо код повернення вказує на збій, тоді як у Dot Net вилучення винятків набагато повільніше, ніж перевірка дійсної умови перед спробою.

Індекси Побудувати індекси на часто запитуваних полях баз даних. Ви можете майже завжди торгувати простором для швидкості.

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

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

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

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

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


5

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


5

Додавши цю відповідь, оскільки я не бачив, щоб вона була включена у всі інші.

Мінімізуйте неявне перетворення між типами та знаком:

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

Специфічний для GCC: Ви можете перевірити це, додавши до свого коду декілька багатослівних прагм,

#ifdef __GNUC__
#  pragma GCC diagnostic push
#  pragma GCC diagnostic error "-Wsign-conversion"
#  pragma GCC diagnostic error "-Wdouble-promotion"
#  pragma GCC diagnostic error "-Wsign-compare"
#  pragma GCC diagnostic error "-Wconversion"
#endif

/* your code */

#ifdef __GNUC__
#  pragma GCC diagnostic pop
#endif

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

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


Ось чому мені подобається, що в OCaml введення між числовими типами повинно бути xplicit.
Гай

Справедливий момент @Gaius - але у багатьох випадках зміна мов не є реальним вибором. Оскільки на C / C ++ настільки широко використовуються корисні, щоб можна було зробити їх більш суворими, навіть якщо конкретний компілятор.
ideaman42

4

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


4

Налаштуйте ОС та фреймворк.

Це може здатися надмірним, але подумайте про це так: Операційні системи та рамки створені для того, щоб робити багато речей. Ваша заявка робить лише дуже конкретні речі. Якщо ви зможете змусити ОС зробити саме те, що потрібно вашій програмі, і ваша програма зрозуміє, як працює фреймворк (php, .net, java), ви могли б набагато краще вийти з обладнання.

Наприклад, Facebook змінив деякі елементи ядра в Linux, змінив функцію memcached (наприклад, вони написали проксі-пам'ять і використовували udp замість tcp ).

Ще один приклад для цього - Window2008. У Win2K8 є версія, якщо ви могли встановити лише основні ОС, необхідні для запуску програм X (наприклад, Web-Apps, Server Apps). Це зменшує значну частину витрат, які ОС має на запущені процеси, і забезпечує кращу продуктивність.

Звичайно, завжди слід вкласти більше обладнання, як перший крок ...


2
Це був би коректний підхід після того, як всі інші підходи виявилися невдалими, або якщо певна функція ОС або Framework відповідала за помітно зниження продуктивності, але рівень знань та контролю, необхідний для її усунення, може бути недоступний для кожного проекту.
Ендрю Нілі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.