Что делает большой и сложный программный продукт медленным? [закрыто]

16

По причине, которая в значительной степени не имеет значения, я установил Delphi 7 еще раз за такое долгое время. Я должен сказать, я был полностью потрясен - таким образом, я не был довольно долгое время. Это не то, как я помню вещи вообще. Установка заняла около 30 секунд. Запуск занял 2 секунды, и он был сразу же применим. Я могу нажать «Выполнить» через секунду после его запуска, и менее чем через секунду пустая программа уже видна и работает. Ура для компьютеров становится намного быстрее!

Но причина, по которой я так поражен, заключается в том, что обычно я использую Visual Studio 2010, который совсем не чувствует себя так быстро. Конечно, Delphi 7 является гораздо меньше , чем система Visual Studio 2010, но у него есть внешний вид того , чтобы все действительно необходимые вещи там: палитра управления, конструктор форм, редактор кода с кодом завершения. Я понимаю, что язык может быть проще, а завершение кода может быть гораздо менее мощным, и IDE может быть не настолько расширяемым и многофункциональным, но все же: я не понимаю, как (т.е. через какой механизм) Множество дополнительных функций (которые я, возможно, еще даже не включил) заставляют систему, подобную Visual Studio, всегда чувствовать себя вялой по сравнению.

Я хотел бы спросить людей, имеющих опыт работы с системами в масштабе Visual Studio: что делает их медленными? Являются ли слои за слоями абстракций, необходимые для сохранения кодовой базы в пределах возможностей человеческого понимания? Это огромное количество кода, которое нужно пройти? Является ли это современной тенденцией к подходам, экономящим время программистов, за (ошеломляюще огромные) расходы в отделе тактов / использования памяти?

Роман Старков
источник
7
Просто: с увеличением массы требуется больше силы для преодоления инерции.
Shog9
Кто-то когда-то сказал мне менеджеров, но я не верю этому вообще.
Михаэль Грассман
1
Это большая часть причины, по которой я до сих пор в основном использую D7 для программирования на Delphi.
GrandmasterB
Самый быстрый код - это тот, который никогда не исполняется.
Генри
4
@romkyns: я считаю, что в современную эпоху много программного обеспечения невероятно раздутое, неоправданно большое и громоздкое. Большая часть программного обеспечения теперь решает те же проблемы, которые были решены десять, даже двадцать лет назад, с небольшим количеством мощности и места. Почему он все еще отстает так же сильно, как и раньше, если не больше? Неэффективность и раздувание.
Orbling

Ответы:

20

Архитектурная космонавтика

Visual Studio 2010 основана на Windows Presentation Foundation. Взгляните на класс Button для WPF. Это 9-й ребенок из базового класса. Он содержит около 5 страниц свойств, методов и событий. За кулисами у него есть еще пять страниц определений стилей, которые описывают его красиво закругленные углы и тонкие анимационные переходы, когда курсор мыши перемещается над ним. Это все для чего-то, что в основном отображает некоторый текст или изображение и производит событие щелчка, когда он обнаруживает нажатие кнопки мыши.

Остановите программу, подобную Visual Studio, в любой случайной точке. Посмотрите на трассировку стека. Скорее всего, очень хорошо, что вы на 20 уровней вглубь стека вызовов и что пять DLL были загружены, чтобы туда попасть.

Теперь сравните эти две вещи с Delphi. Бьюсь об заклад, вы обнаружите, что кнопка Delphi имеет только 20 свойств, методов и событий. Могу поспорить, что Delphi IDE имеет трассировку стека глубиной всего 5-7 уровней. Потому что, когда компьютеры работали медленнее, вы просто не могли взять на себя накладные расходы Visual Studio 2010 без IDE, затрачиваемого на запуск 40 минут :-)

Один лучше другого? Ну, я обычно могу сказать программе Delphi, когда она загружается, потому что она выглядит плоской, цвета приглушены (возможно, 8-битные?), И нет тонкого затенения или анимации. Я просто чувствую себя дешевым в эти дни. Дешево, но быстро.

Нам лучше? Это вопрос к философам, а не к кодерам.

Джей Биверс
источник
4
Программа Delphi не выглядит плоской. Скорее программист программирует программу, чтобы она выглядела плоской. Вы можете создавать красивые, современные, полноцветные интерфейсы с Delphi, как в C # или C ++.
GrandmasterB
2
Это проницательный ответ; но я не уверен, что это завершено. Visual Studio 2008 (предшественник 2010 года) не содержит WPF и все еще работает медленнее, чем Delphi 7. Вы все еще сказали бы то же самое о глубине стека вызовов и количестве загруженных библиотек DLL?
Тимви
3
@Timwi Да, конечно. Мое мнение было не столько о пороках WPF (мне действительно нравится WPF), сколько о том, как мы склонны добавлять слои к слоям абстракции программного обеспечения, когда предоставляется выбор. Возможно, в Visual Studio 2008 было не так много накладных расходов, но, как вы заметили, этого было вполне достаточно :-)
Джей Биверс
@GrandmasterB, я не осуждаю Delphi, потому что он содержит меньше предположений и более простые библиотеки. WPF был разработан с учетом того, что аппаратное ускорение графического процессора позволит программам использовать более глубокие цвета, частую анимацию, альфа-смешение, тени и т. Д. Delphi была разработана в то время, когда эти предположения не могли быть сделаны. Не могли бы вы реализовать все это в Delphi? Конечно, но вам нужно было бы добавить много кода, чтобы понять поведение кнопки WPF. С другой стороны, кнопка Delphi не соответствует требованиям к процессору, памяти и графическому процессору, к которой у кнопки WPF относится и вопрос @ OP.
Джей Биверс
10
Ваш аргумент в пользу плоского и простого пользовательского интерфейса полностью аннулирован новым интерфейсом Windows 10 «Modern». Теперь у нас есть все, что нужно для создания плоских, квадратных, простых кнопок, как у нас было 30 лет назад.
gbjbaanb
11

Я хотел бы спросить людей, имеющих опыт работы с системами в масштабе Visual Studio: что делает их медленными? Являются ли слои за слоями абстракций, необходимые для сохранения кодовой базы в пределах возможностей человеческого понимания? Это огромное количество кода, которое нужно пройти? Является ли это современной тенденцией к подходам, экономящим время программистов, за (ошеломляюще огромные) расходы в отделе тактов / использования памяти?

Я думаю, что вы догадались, что некоторые из них, но я хотел бы предложить то, что я считаю самым важным фактором, работая над достаточно большой базой кода (не уверен, что он такой же большой, как Visual Studio - в миллионах строк кода) категория и около тысячи плагинов) в течение примерно 10 лет и наблюдения явления происходят.

Это также немного менее спорным, так как он не входит в API, или функции языка или что-нибудь подобное. Это относится к «затратам», которые могут породить дебаты, а не «расходы», и я хочу сосредоточиться на «расходах».

Свободная координация и наследие

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

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

У нас было бы как дерево KD для ускорения одного физического движка, другого для нового физического движка, который часто работал параллельно со старым, у нас были бы десятки реализаций октодеревьев для различных алгоритмов сетки, другое дерево KD для рендеринга , подбор и т. д. и т. д. и т. д. Это все большие, громоздкие древовидные структуры, используемые для ускорения поиска. Каждый из них может занимать сотни мегабайт в гигабайтах памяти для ввода очень среднего размера. Они не всегда создавались и использовались постоянно, но в любой момент времени 4 или 5 из них могли бы быть в памяти одновременно.

Теперь все они хранили одни и те же данные, чтобы ускорить их поиск. Вы можете представить ее как аналогичную старую аналогичную базу данных, которая хранит все свои поля в 20 различных избыточных картах / словарях / деревьях B + одновременно, одинаково организованных по одним и тем же ключам, и постоянно ищет их все. Теперь мы берем в 20 раз больше памяти и обработки.

Кроме того, из-за избыточности у нас мало времени на оптимизацию любого из них с помощью стоимости обслуживания, которая идет с этим, и даже если бы мы это сделали, это дало бы только 5% эффекта, который в идеале был бы.

Что вызывает это явление? Слабая координация была причиной номер один, которую я видел. Многие члены команды часто работают в своих изолированных экосистемах, разрабатывая или используя сторонние структуры данных, но не используя те же структуры, которые использовали другие члены команды, даже если они были откровенно вопиющими дубликатами тех же проблем.

Что заставляет это явление сохраняться? Наследие и совместимость были главной причиной, которую я видел. Поскольку мы уже заплатили за реализацию этих структур данных, а большие объемы кода зависели от этих решений, зачастую было слишком рискованно пытаться объединить их с меньшим количеством структур данных. Несмотря на то, что многие из этих структур данных были концептуально избыточными, они не всегда были похожи друг на друга в своих интерфейсах. Поэтому замена их была бы большим, рискованным изменением, а не просто позволила бы им потреблять память и время обработки.

Эффективность памяти

Обычно использование памяти и скорость, как правило, связаны, по крайней мере, с общим объемом. Вы часто можете обнаружить медленное программное обеспечение по тому, как оно загружает память. Не всегда верно, что увеличение объема памяти приводит к замедлению, поскольку важна «горячая» память (к какой памяти обращаются все время - если программа использует загрузочную память, но только 1 мегабайт используется все время, то это не так уж важно по скорости).

Таким образом, вы можете обнаружить потенциальных свиней на основе использования памяти в большинстве случаев. Если приложение при запуске занимает от десятков до сотен мегабайт памяти, оно, вероятно, не будет очень эффективным. Десятки мегабайт могут показаться маленькими, когда у нас есть гигабайты DRAM в наши дни, но самые большие и самые медленные кэши ЦП все еще находятся в мизерном диапазоне мегабайт, а самые быстрые - в диапазоне килобайт. В результате программа, которая использует 20 мегабайт только для запуска и ничего не делает, на самом деле все еще использует довольно «много» памяти с точки зрения аппаратного ЦП, особенно если все 20 мегабайт этой памяти будут доступны повторно и часто, когда программа работает.

Решение

Для меня решение состоит в том, чтобы искать более скоординированные, меньшие команды для создания продуктов, которые могут отчасти отслеживать свои «расходы» и избегать «покупки» одних и тех же товаров снова и снова и снова.

Стоимость

Я окунусь в более противоречивую сторону «затрат», чуть-чуть с феноменом «расходов», который я наблюдал. Если язык в конечном итоге приходит с неизбежным ценником для объекта (например, тот, который обеспечивает отражение во время выполнения и не может вызвать непрерывное выделение для серии объектов), этот ценник является дорогостоящим только в контексте очень гранулированного элемента, такого как одного Pixelили Boolean.

Тем не менее, я вижу много исходного кода для программ, которые обрабатывают большую нагрузку (например, имеют дело с сотнями тысяч до миллионов Pixelили Booleanэкземпляров), оплачивая эти затраты на таком детальном уровне.

Объектно-ориентированное программирование может усугубить это. И все же это не стоимость «объектов» как таковых или даже ООП по вине, а просто то, что такие расходы оплачиваются на таком гранулярном уровне крошечного элемента, который будет создан миллионами.

Так что я наблюдаю другие явления «затрат» и «расходов». Стоимость - копейки, но копейки складываются, если мы покупаем миллион банок содовой по отдельности вместо того, чтобы договариваться с производителем о крупной покупке.

Решением здесь для меня является «массовая» покупка. С объектами все в порядке даже в тех языках, в которых каждый имеет цену в несколько копеек, при условии, что эта стоимость не оплачивается отдельно в миллион раз за аналогичный эквивалент банки с газировкой.

Преждевременная оптимизация

Мне никогда не нравилась формулировка Кнута, используемая здесь, потому что «преждевременная оптимизация» редко заставляет реальные производственные программы работать быстрее. Некоторые интерпретируют это как «ранняя оптимизация», когда Кнут имел в виду больше как «оптимизация без надлежащих знаний / опыта, чтобы узнать ее истинное влияние на программное обеспечение». Во всяком случае, практический эффект от истинной преждевременной оптимизации часто собирается сделать программное обеспечение медленнее , так как ухудшение ремонтопригодности средств есть немного времени , чтобы оптимизировать критические пути , которые действительно имеет значения .

Это последнее явление, которое я наблюдал, когда разработчики, стремящиеся сэкономить копейки на покупке одной банки содовой, которую никогда больше не купят, или, что еще хуже, дом, тратили все свое время, зажимая копейки (или, что еще хуже, мнимые копейки из неспособность понять их компилятор или архитектуру аппаратного обеспечения), когда миллиарды долларов были потрачены впустую в другом месте.

Время очень ограничено, поэтому попытка оптимизировать абсолюты без надлежащей контекстной информации часто лишает нас возможности оптимизировать места, которые действительно важны, и, таким образом, с точки зрения практического эффекта, я бы сказал, что «преждевременная оптимизация делает программное обеспечение намного медленнее. "

Проблема в том, что существуют типы разработчиков, которые возьмут то, что я написал выше об объектах, и попытаются установить стандарт кодирования, который запрещает объектно-ориентированное программирование или что-то в этом роде. Эффективная оптимизация - это эффективная расстановка приоритетов, и она абсолютно бесполезна, если мы тонем в море проблем с техническим обслуживанием.

Томас Оуэнс
источник
2
Другими словами, технический долг. Технический долг, который никогда не погашается.
Роберт Харви
1
Роберт прав. Одна ошибка от парня, двести ошибок --forceот менеджеров, которые кричали: «Вы будете уволены, если не реализуете это к завтрашнему дню», которые уничтожают годы хорошей практики разработки программного обеспечения, TDD, модульного тестирования и любого человеческого и нормального принципа программирования. Плюс еще два раза, когда вы устали ... тот парень, который покинул компанию из-за того, что был уволен без причины и испортил базу кода ... эти прекращенные библиотеки, которые вы никогда не обновляли ... и вот оно у вас: восхитительная база кода спагетти и раздутый софт. Приятного аппетита
user3834459
2
Интересно, особенно из-за того, что вы видели чрезмерное использование гранулярности. Я поймал себя на том, что иногда делаю нечто подобное, и в результате получаю плохую работу. Это очень похоже на ваш ответ несколько дней назад об использовании коллекций и массовых алгоритмов в предпочтении перед чрезмерной гранулярностью . Я не могу поверить, что ответ не был более оценен за его глубину. Это заставляет меня переосмыслить несколько проектов, которые я построил за эти годы. Интересно, почему эти методы не получили более широкого распространения?
Майк поддерживает Монику
2
@ Майк, я немного сломан, когда пытаюсь продвигать больше ориентированного на данные мышления. Это популярно в игровой индустрии, где они пытаются использовать каждый дюйм оборудования. Тем не менее, это по общему признанию снижает гибкость. Если у вас есть абстрактный класс пикселей, вы можете делать сумасшедшие вещи, например, иметь одно изображение, которое смешивает два или более разных формата пикселей! Тем не менее, когда мы имеем дело с критическими путями, вероятно, ни одно изображение не выиграет от такого уровня гибкости, и производительность начинает становиться реальной проблемой для всего, что связано с изображениями и пикселями.
1
В старые добрые времена я реализовал некоторый код для обхода графических API и прямого доступа к пикселям в памяти для критической части моего кода. Разница между многими уровнями абстракции и прямым доступом была примерно в 100 раз, что имело значение на компьютере в те дни. Теперь ваши компьютеры достаточно быстры, чтобы вы могли пробираться через любое количество абстракций, если это необходимо.
Михаил Шопсин