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


30

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

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


3
Повідомлення модератора : будь ласка, не використовуйте коментарів для розширеного обговорення або для розміщення жалюгідних відповідей. Ви можете використовувати чат для обговорення цього питання; попередні коментарі були переміщені туди.
Жил "ТАК - перестань бути злим"

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

Відповіді:


42

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

У вашому конкретному випадку ваш приклад пошуку підключених компонентів, можливо, працював для графіків розміром до вузлів. Однак, якби ви спробували графік зі 100 000 вузлами, алгоритм вашого викладача, ймовірно, зміг би це за 1 секунду, тоді як ваш алгоритм мав би (залежно від того, наскільки складною була складність) за 1 годину, 1 день чи, можливо, навіть на 1 вічність.100100.000

Дещо поширена помилка, яку студенти роблять у нашому курсі алгоритмів, полягає в тому, щоб повторити такий масив:

while array not empty
    examine first element of array
    remove first element from array

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

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

while array not empty
    examine last element of array
    remove last element from array

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

У моїй псевдокодовій мові "видалення елемента з масиву" зміщує всі елементи праворуч від елемента, який видаляється, на одну позицію зліва. Це робить видалення останнього елемента операцією оскільки для цього нам потрібно взаємодіяти лише з 1 елементом. Видалення першого елемента є O ( n ), оскільки для того, щоб видалити перший елемент, нам потрібно зрушити всі інші n - 1 елементів на одну позицію вліво.O(1)O(n)n1

Дуже основна складна вправа - довести, що перша програма зробить операції, тоді як друга програма використовує лишеnоперацій. Якщо ви підключитеn=100.000,ви побачите, що одна програма значно ефективніша за іншу.12n2nn=100.000

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

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


10
"So long as you are not dealing with huge data sets you will be fine not knowing complexity"Це часто правда, але не завжди так. Наприклад, O(n!)алгоритм не буде життєздатним навіть для відносно невеликих наборів даних. Якщо ви використовуєте O(n!)алгоритм, де ви могли б використовувати O(n^2)вашу програму, на виконання даних на розмір даних 10 буде потрібно 36 288 разів довше . На даних розміром 20 ви дивитеся на 2,4 квинтільйонні операції.
рейраб

1
Я думаю, що у відповідь слід включити приклад @ reirab. Це більш драматично і доводить вашу думку більш рішуче. І мене особисто покусали такі алгоритми, перш ніж я навчився обчислювальній складності.
Сіюань Рен

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

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

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

26

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

Справа в тому, що в більшості випадків у 50 000 разів повільніше це не має значення (якщо ви, звичайно, не працюєте в Google).

Якщо операція, яку ви виконуєте, займає мікросекунду або якщо ваш N ніколи не перевищує певний поріг (велика частина кодування, що робиться нині), це НІКОЛИ не має значення. У таких випадках роздуми про складність обчислень лише змусять вас витрачати час (і, швидше за все, гроші).

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

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

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

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


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

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

4
Коли ви знаєте, що набір даних невеликий, у всіх випадках ви можете піти з подібних речей. Ви повинні бути дуже обережними над зайвою складністю у предметах, що називаються в циклі, хоча - не так давно я таким чином скоротив хвилину виконання на секунду. Одного разу я також стикався з проблемою O (n ^ 8) (перевірка даних.) Багато піклування зменшилось до 12 годин.
Лорен Печтел

7
Я ніколи не знаходив необхідності думати про складність обчислювальної техніки під час циклу всередині циклу O (M * N), оскільки операція завжди дуже швидка або M і N такі малі. - Як не дивно, аргумент, який ви наводите, свідчить про те, що ви думали про складність обчислень. Ви вирішили, що це не важливе питання для того, що ви робите, і можливо, це правильно, але ви все ще знаєте про існування цього питання, і якщо воно коли-небудь створюватиме проблему, ви могли б відреагувати на це, перш ніж серйозні наслідки трапляться на рівень користувача.
Wrzlprmft

4
Передчасна оптимізація - корінь усякого зла, але передчасна песимізація - корінь принаймні багато роздратованих користувачів. Можливо, вам не знадобиться вирішити відношення рецидиву, але якщо ви, принаймні, не здатні розповісти різницю між O (1), O (N) і O (N ^ 2), особливо коли ви Ви вкладаєте петлі, комусь доведеться пізніше прибирати безлад. Джерело: меси, які мені довелося прибрати пізніше. Коефіцієнт 50 000 настільки великий, що ви могли краще знати, чи можете ви дозволити собі це пізніше , коли ваші внески зросли.
Jeroen Mostert

14

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

Незважаючи на те, щоб сказати, я самоучка. Я ніколи не стикався з нотацією O, поки не почав інтерв'ю кілька років тому. Це ніколи не з'являється в моїй професійній роботі, ОКРЕМУ під час співбесіди. Тому мені довелося засвоїти основи, щоб просто вирішити це питання в інтерв'ю.

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

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

Удачі тобі!


2
Отже, ваша відповідь «так»?
Рафаель

6
TL; DR: "так". Однак, на мій досвід, ви не збираєтеся говорити про складність обчислень у більшості робочих місць після того, як вас найнять. Так, знайте ваші структури даних та їхню ефективність, але просто знаючи, що алгоритм є O (n) або що не є хорошим програмістом. Набагато краще зосередитись на написанні хорошого коду та згодом оптимізації гарячих точок. Читання та ремонтопридатність, як правило, важливіші для більшості кодів, ніж продуктивність.
Скотт Шафер

3
Я думаю, що може статися, що складність з'являється в корпоративних умовах, але перше справжнє занепокоєння компаній - це доставка : якщо це працює, це досить добре, поки не буде доступного бюджету на покращення програми, або клієнт повернеться скаржитися на погану вистави. У ситуаціях b2b для adhoc-проектів це, мабуть, досить рідко. На b2c, або на високо конкурентоспроможних ринках (поза продуктами на зберіганні), можливо, це з'явиться частіше, з прямим ефектом підвищення рівня вступу для нових найм.
didierc

4
@didierc "Досить добре" - це те, що весь час ламає речі.
Рафаель

1
@didierc 1) Ну, люди з твердим фоном в CS робити (сподіваюся) мати хорошу інтуїцію для того, що є правильним , а що ні, в той час як Ad-Hoc вирішувачі можуть зробити «просту» помилку. Забезпечення того, що виконання після мультиплікаційних компіляцій саме те, що було визначено, є нетривіальним, і це не вирішена проблема. 2) Ні .
Рафаель

9

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

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

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

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


1
Я думаю, що ти, як правило, маєш правильне уявлення, але "суб'єктивне" не описує це питання адекватно; «обставинне» було б кращим словом. Крім того, можна писати дуже повільні програми, які не працюють на великій кількості даних. Нещодавно я відповів на запитання в math.se про представлення / зберігання поліномів. Це, як правило, включає досить малу кількість даних, наприклад, ~ 1000-термінових поліномів є типовими; але існують величезні різниці в продуктивності (сотні чи тисячі секунд проти кількох секунд на множення) залежно від реалізації.
Фіз

4

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

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

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


3

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

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

Програміст noobish може робити:

  • розробляти великі бази даних - він не повинен знати, як це працює всередині, все, що він повинен знати, - це правила розробки баз даних. Він знає такі речі, як: що слід індексувати, ... де краще зробити надмірність даних, де його немає ...
  • робити ігри - він просто повинен вивчити, як працює деякий ігровий движок і слідувати його парадигмам, ігри та комп’ютерна графіка - це досить великі проблеми з даними. Розглянемо 1920 * 1080 * 32 біт = cca 7,9 МБ для однієї картини / кадру ... при 60 FPS, це не менше 475 Мб / с. Вважайте, що лише одна непотрібна копія повноекранного зображення витрачає близько 500 Мб пропускної здатності в секунду. Але йому не потрібно про це дбати, адже він використовує лише двигун!

Програміст noobish не повинен робити:

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

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

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


1
Цю відповідь можна було б покращити, якби вона використовувала більш нейтральну мітку або взагалі ніяку мітку, як і інша відповідь, що використовувала термін "некомпетентний програміст".
Диск Moby

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

3

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

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

n2

Я б чесно наважився порівняти ситуацію того, щоб знати, коли застосовувати поняття складності обчислювальної техніки (і знати, коли їх можна сміливо ігнорувати) із дещо поширеною практикою (за межами світу Java) впровадження деякого коду, що чутливий до продуктивності в C, і не залежно від продуктивності. речі в Python тощо. (Окрім цього, в розмові про Джулію це називалося "стандартним компромісом" .) Знання, коли не потрібно думати про продуктивність, економить час програмування, який теж досить цінний товар.

І ще один момент полягає в тому, що знання складності обчислювальної техніки не допоможе вам автоматично оптимізувати програми; вам потрібно зрозуміти більше пов'язаних з архітектурою речей, таких як локація кешу, [іноді] конвеєрна робота, а зараз теж паралельне / багатоядерне програмування; останній має як власну теорію складності, так і практичні міркування; смак останнього з документа SOSP 2013 "Кожна схема блокування має свою п'ятнадцять хвилин слави. Жодна з дев'яти схем блокування ми не вважаємо стабільно вищою за будь-яку іншу в усіх цільових архітектурах або робочих навантаженнях. Строго кажучи, щоб шукати оптимальності, Таким чином, алгоритм блокування повинен бути обраний на основі апаратної платформи та очікуваного навантаження ".


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

1
На практиці алгоритми Шлеміеля Живописця набагато частіше, ніж сортування O (n ^ 2).
Пітер Мортенсен

-1

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

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

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

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

Але вони не можуть сховатися від цієї техніки.


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

@Raphael: Я не виступаю за інший підхід - це ортогональний.Big-O - це базові знання для розуміння алгоритмів, тоді як пошук продуктивності в неіграшному програмному забезпеченні - це те, що ви робите після написання та запуску коду, а не раніше. (Іноді вчені цього не знають, тому вони продовжують викладати gprof, роблячи більше шкоди, ніж користі.) Роблячи це, ви можете чи не можете виявити, що проблема полягає у використанні алгоритму O (n * n), тож вам слід вміти це визнати. (І big-O - це лише математично визначена властивість алгоритмів, а не інша тема.)
Майк Данлі

"І big-O - це лише математично визначена властивість алгоритмів, а не інший предмет." - це неправильно, і це небезпечно. "Big-Oh" визначає класи функцій ; сама по собі вона взагалі не має нічого спільного з алгоритмами.
Рафаель

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