Инфляция программного обеспечения с точки зрения ресурсов процессора — почему новые версии приложения порой гораздо медленнее старых?

в 14:56, , рубрики: Железо, закон Мура, Процессоры, Софт

Прелюдия

Это был обычный вечер четверга. Я вернулся с работы, сел за ноутбук, включил его, запустил Skype и начал привычно ждать, когда же он наконец загрузится полностью и целиком. И тут неожиданно я задумался — а почему он так долго загружается, да еще и система явно тяжело переносит этот процесс?

Я решил заглянуть в Task Manager, чтобы оценить, сколько ресурсов потребляет Skype в фоновом режиме. Но для начала небольшие предварительные расчеты. А сколько вообще это должно потреблять ресурсов? Я сейчас говорю про фоновый режим. Т.е. когда никакой видеосвязи нет, я ни с кем не говорю даже по микрофону. Все, что есть, это список контактов, который отображается в виде иконок и имен, и меню, в котором можно что-то выбрать.

Т.е. это одна форма, по сути, из которой можно запустить дополнительные меню. На этой форме один список. И текстовое поле для ввода сообщений кому-то, несколько кнопок. Лет 15 назад, когда я писал на Delphi, такое приложение (с одной формой) весило бы пару сотен килобайт. Конечно, с тех пор среды разработки стали потреблять гораздо больше ресурсов, компоненты визуальные стали богаче. Однако даже с учетом этого прогресса Skype в фоновом режиме должен весить где-то мегабайт 10 максимум. Ведь я же ни с кем не говорю и не звоню, на что там еще можно столько потратить?

Можно взглянуть на это дело и с другой стороны, как говорят математики, на эквивалентность. Без видеосвязи и разговоров по микрофону Skype предоставляет возможность просмотреть, кто из собеседников на данный момент в сети, а также отправить ему текстовое сообщение, ну и получить в ответ от кого-то текстовое сообщение. Т.е. это по сути ICQ — так что, ну наверное, в фоновом режиме, скорее всего, Skype должен и занимать в памяти примерно столько как ICQ? А теперь проверим на практике эти расчеты. Смотрим в TaskManager на потребление памяти:

image

Skype занимает в памяти 158 Мбайт? Вы это серьезно, учитывая, что QIP занимает 35 Мбайт? Ладно, 35 Мбайт это тоже пожалуй многовато, и с этим следовало бы разобраться, но моя заметка не об этом. Мы сейчас о Skype. Почему он занимает столько ресурсов — почти в 5 раз больше, чем QIP? На одну форму со списком контактов это как-то многовато, Вы не находите?

Что интересно, эта проблема волнует не только меня, если вы вобьете в Google "Why does skype consume so much memory", то там вывалится просто портянка различных обсуждений на форумах, почему новые версии Skype так много весят. Особенно радуют ответы. Например, реальный ответ на форуме сообщества Skype (я привожу мой вольный перевод ответа):

А почему вы считаете, что это много? Современные компьютеры имеют 4-8 Гбайт оперативной памяти. 140 Мбайт это такая мелочь по современным меркам, что вы даже этого не заметите при запуске.

Ага, ну да. Конечно. Если так все разработчики ПО будут рассуждать, то этак "никаких волостей не напасешься". Вопрос-то не в том, что мне памяти для Skype жалко (да и жалко тоже). Вопрос в том, что такого нового по функциональности прибавилось в новых версиях Skype (по сравнению со старыми), что они требуют так много памяти?

Но это-то ладно.Куда больше меня интересовал другой вопрос — процессор со Skype в фоновом режиме тоже не особо расслаблялся и периодически показывал даже полную загрузку. Возникает вопрос «Почему и как от этого избавиться?». На самом деле вопрос должен звучать так — как вообще разработчики умудряются создать такие громоздкие приложения? И что с этим делать?

Немного истории

Конечно, любой посетитель данного сайта наверняка хоть раз слышал про закон Мура о повышении производительности систем. В статье Free lunch is over приводится такая любопытная картинка:

image

Как видно, где-то в 2004-м процессоры достигли потолка в плане тактовой частоты. И последние 10 лет эта частота особо не растет. Следует ли из этого, что закон Мура перестал выполняться? Вообще-то, нет, и в статье ясно и четко объясняется почему. Просто производительность наших компьютеров теперь растет за счет других факторов (кэш и многоядерность). Однако загвоздка в том, что обычным одно-поточным приложениям эти факторы ускориться не помогут. И вот здесь возникает проблема. Дело в том, что многие производители ПО в наши дни ведут себя так, как будто на дворе по прежнему 80-е или 90-е, и оптимизация ПО в плане уменьшения количества тактов не представляет особой проблемы — просто можно немножко подождать, и процессоры станут гораздо быстрее.

Это справедливо не только для Microsoft, однако я сосредоточусь на конкретных примерах для нее. Джоэл Спольски в своей статье упоминает, что Microsoft удалось одержать верх над Lotus в 80-х годах в битве между Excel и 123 за счет того, что менеджеры Lotus допустили одну критическую ошибку — они попытались провести оптимизацию приложения. Конкретно они попытались ужать приложение так, чтобы оно всегда гарантированно умещалось в 640 Кбайт оперативной памяти. Они убили на это полтора года, и за это время Редмонд захватил рынок с помощью Excel, поскольку к этому моменту в строй вступали компьютеры с гораздо большими объемами оперативной памяти. Это решение очень дорого обошлось Lotus.

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

Инфляция

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

В английском языке есть устойчивая идиома, которая на русском звучит как «пытаться починить то, что не было сломано». Ситуация с ПО в последние 10 лет напоминает очень сильно эту идиому. Skype является одним из ярких примеров этого. Судя по форумам, эта проблема с памятью в старых версиях Skype не существовала, например, в версиях 3.x. Что такого усовершенствовали в продукте с тех пор, что он стал стоить настолько дорого в плане оперативной памяти?

То же самое, кстати, касается различных чат-приложений. Лет 15 назад чат, который за раз занимает 30 Мбайт оперативной памяти, выглядел нонсенсом. Однако сейчас это уже норма, хотя что же такого предоставляют нам чаты нынешние, чего не предоставлялось в то время?

Не стоит забывать и Microsoft Office. По-моему, версия для XP удовлетворяла всех. Конечно, как и любой продукт, она имела свои недостатки. Но были ли они настолько критичны, что потребовалось выпускать версии 2007, 2010 и т.д.? Я делаю в них те же самые документы, однако теперь приходится ждать гораздо дольше, пока эти системы загрузятся.

В оправдание мы слышим, что новые версии содержат новые возможности. Это да, я не отрицаю, но разве не выглядит странным, что при этом старые возможности требуют больше ресурсов?

Модульность и оптимизация

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

Вернемся опять же к Skype. Сейчас он очевидно сделан так, что при простом входе в систему сразу загружается в оперативную память масса модулей, ответственных непосредственно за звук, видео и т.д. Это при том, что обычный вход требует лишь списка пользователей и возможности обмена текстом. Эту систему можно было сделать иначе, загружая лишь самое необходимое. И только когда пользователь хочет реально начать видео-обмен, подгружается все остальное.

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

Представим себе, что разработчик каждой библиотеки сделал свою библиотеку на 5% медленнее, чем она могла бы быть, если бы он затратил дополнительные усилия на оптимизацию. Пусть библиотека 1 в своей работе использует библиотеку 2, а та библиотеку 3, а та библиотеку 4. В этом случае цепочка из 15 библиотек в случае аккумуляции задержек получает результат 1.05^15 = 2.07, т.е. приложение в худшем случае будет работать в два раза медленнее, чем любой из компонентов.

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

Альтернативные примеры

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

В мире ПО тоже такие примеры есть. В свое время мне очень понравился Erlang, который построен на концепции множества независимых легковесных процессов, которые объединены лишь общими сообщениями (это позволяет максимально использовать многоядерность). Кроме того, в этой среде действует принцип, который был явно позаимствован из интерпретаторов LISP — что каждый модуль и функцию можно загрузить и перегрузить на ходу при необходимости (и то же самое касается любого процесса).

Для сравнения, на Glassfish, если вы изменили один из нескольких сотен или тысяч классов, вам надо переустановить весь модуль (war/ear/jar). Горячая замена функций или классов на ходу там есть, но реализована очень слабо по сравнению с Erlang.

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

Автор: spirit1984

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js