Использует ли использование больших библиотек по сути медленный код?

У меня есть психологический тик, который заставляет меня неохотно использовать большие библиотеки (например, GLib или Boost) на языках нижнего уровня, таких как C и С++. На мой взгляд, я думаю:

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

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

Torvalds rant (спорный, хотя он и есть) не совсем успокаивает меня.

Есть ли какая-то основа для моего мышления, или я просто необоснованна и/или невежественна? Даже если я использую только одну или две функции большой библиотеки, связываясь с этой библиотекой, я буду нести накладные расходы на производительность во время выполнения?

Я уверен, что это тоже зависит от конкретной библиотеки, но мне обычно интересно узнать, будут ли большие библиотеки на техническом уровне внедрять неэффективность.

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

Пожалуйста, уберите меня из моих страданий!

Ответ 1

Даже если я использую только одну или две функции большой библиотеки, связываясь с этой библиотекой, я буду нести накладные расходы на производительность во время выполнения?

В общем, нет.

Если в рассматриваемой библиотеке не много кода, зависящего от позиции, тогда будет начальная стоимость, в то время как динамический компоновщик выполняет перемещение по библиотеке при ее запросе. Обычно эта часть запуска программы. Эффект производительности во время выполнения не превышает этого.

Линкеры также умеют удалять "мертвый код" из статически связанных библиотек во время сборки, поэтому любые статические библиотеки, которые вы используете, будут иметь минимальные накладные расходы. Производительность даже не входит в нее.

Честно говоря, вы беспокоитесь о неправильных вещах.

Ответ 2

Я не могу комментировать GLib, но имейте в виду, что большая часть кода в Boost предназначена только для заголовков и, учитывая принцип C++, согласно которому пользователь платит только за то, что он использует, библиотеки довольно эффективны. Есть несколько библиотек, которые требуют, чтобы вы ссылались на них (regex, файловая система), но это отдельные библиотеки. С Boost вы не связываетесь с большой монолитной библиотекой, а только с более мелкими компонентами, которые вы используете.

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

Ответ 3

Boost не является большой библиотекой.

Это коллекция многих небольших библиотек. Большинство из них настолько малы, что они содержатся в заголовке или двух. Использование boost::noncopyable не перетаскивает boost::regex или boost::thread в ваш код. Это разные библиотеки. Они просто распространяются как часть одной библиотеки. Но вы платите только за те, которые вы используете.

Но, говоря вообще, поскольку большие библиотеки существуют, даже если Boost не является одним из них:

Есть ли какая-то основа для моего мышления, или я просто необоснованна и/или невежественна? Даже если я использую только одну или две функции большой библиотеки, связываясь с этой библиотекой, я буду нести накладные расходы на производительность во время выполнения?

Нет оснований, более или менее. Вы можете проверить его самостоятельно.

Напишите небольшую программу на C++ и скомпилируйте ее. Теперь добавьте к нему новую функцию, которая никогда не вызывается, а определяется. Скомпилируйте программу еще раз. Предполагая, что оптимизация включена, она убирается компоновщиком, потому что она не используется. Таким образом, стоимость включения дополнительного неиспользуемого кода равна нулю.

Конечно, есть исключения. Если код запускает любые глобальные объекты, они могут быть удалены (поэтому включение заголовка iostream увеличивает размер исполняемого файла), но в целом вы можете включить столько заголовков и ссылку на столько библиотек, сколько захотите, и это не повлияет на размер, производительность или использование памяти вашей программы *, если вы не используете какой-либо добавленный код.

Другим исключением является то, что если вы динамически ссылаетесь на .dll или .so, вся библиотека должна быть распределена и поэтому не может быть удалена из неиспользуемого кода. Но библиотеки, статически скомпилированные в ваш исполняемый файл (как статические библиотеки (.lib или .a), так и включенные заголовочные файлы, обычно могут быть обрезаны компоновщиком, удаляя неиспользуемые символы.

Ответ 4

Большая библиотека будет, с точки зрения производительности кода:

  • занимают больше памяти, если он имеет двоичный файл времени выполнения (большинство частей boost не требуют исполняемых файлов, они "только для заголовка" ). Хотя ОС будет загружать только фактически используемые части библиотеки в ОЗУ, она по-прежнему может загружать больше, чем вам нужно, потому что зернистость загружаемого файла равна размеру страницы (4 Кбайт только в моей системе).
  • потребуется больше времени для загрузки динамическим компоновщиком, если, опять же, ему нужны исполняемые файлы времени исполнения. Каждый раз, когда ваша программа загружается, динамический компоновщик должен соответствовать каждой функции, которой требуется внешняя библиотека, чтобы содержать ее фактический адрес в памяти. Это занимает некоторое время, но немного (однако, это имеет значение в масштабе загрузки многих программ, таких как запуск среды рабочего стола, но у вас нет выбора там).

    И да, при каждом вызове внешней функции общей (динамически связанной) библиотеки

    потребуется один дополнительный прыжок и несколько настроек указателя во время выполнения,

с точки зрения производительности разработчика:

  • добавить внешнюю зависимость. Вы будете зависить от кого-то другого. Даже если это бесплатное программное обеспечение библиотеки, вам потребуются дополнительные расходы для его изменения. Некоторые разработчики низкоуровневых программ veeery (я говорю о ядрах ОС) ненавидят полагаться на кого-либо - на то, что их профессиональный перк. Таким образом, тирады.

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

  • Большие библиотеки обычно содержат концепты, специфичные для библиотеки, которые требуют времени для понимания. Рассмотрим Qt. Он содержит сигналы и слоты и moc -связанную инфраструктуру. По сравнению с размером всего Qt их изучение занимает небольшую часть времени. Но если вы используете небольшую часть такой большой библиотеки, это может быть проблемой.

Ответ 5

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

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

Ответ 6

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

  • Если ваш проект сам по себе предназначен для использования в качестве библиотеки или фреймворка, вы можете в конечном итоге подтолкнуть выбор своей платформы к разработчикам, которые используют вашу библиотеку.

  • Если вы распространяете свой проект в исходной форме, вы можете в конечном итоге повысить доступ к платформенным технологиям у своих конечных пользователей.

  • Если вы не статически связываете все выбранные фреймворки и библиотеки, вы можете в конечном итоге обременять своих конечных пользователей проблемами с версиями библиотеки.

  • Скомпилируйте время разработки производительности разработчика. Инкрементная привязка, предварительно скомпилированные заголовки, правильное управление зависимостями заголовков и т.д. Могут помочь управлять временем компиляции, но не устраняют проблемы производительности компилятора, связанные с огромным количеством встроенного кода, внедряемого некоторыми платформами.

  • Для проектов, которые распространяются как источник, время компиляции влияет на конечных пользователей проекта.

  • Многие технологии платформ имеют свои собственные требования к среде разработки. Эти требования могут накапливаться, что затрудняет и требует много времени, чтобы новые разработчики проекта могли реплицировать среду, необходимую для компиляции и отладки.

  • Использование некоторых технологий платформы создает новый язык программирования для проекта. Это затрудняет участие новых разработчиков.

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

Ответ 7

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

Однако при каждом загрузке не будет накладных расходов.

Если вы не хотите использовать all для повышения, тогда не делайте этого. Он модульный, поэтому вы можете использовать нужные части и игнорировать остальные.

Ответ 8

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

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

Реальный ответ для конкретной библиотеки обычно зависит от ее общей структуры. Легко думать о "Boost" как о чем-то огромном. Фактически, это огромная коллекция библиотек, большинство из которых индивидуально довольно малы. Вы не можете сказать много (значимо) о Boost в целом, потому что отдельные библиотеки написаны разными людьми, с разными приемами, целями и т.д. Некоторые из них (например, Format, Assign) действительно медленнее, чем почти все вы, скорее всего, будете делать это самостоятельно. Другие (например, Pool) предоставляют вещи, которые вы можете сделать сами, но, вероятно, не будете, чтобы получить хотя бы незначительные улучшения скорости. Некоторые (например, uBlas) используют мощную магию шаблонов, чтобы работать быстрее, чем любой, но крошечный процент из нас может надеяться достичь самостоятельно.

Есть, конечно, немало библиотек, которые действительно являются отдельными большими библиотеками. В довольно многих случаях это действительно медленнее, чем вы сами пишете. В частности, многие (большинство?) Из них пытаются быть гораздо более общим, чем почти все, что вы, вероятно, будете писать самостоятельно. Хотя это не обязательно приводит к более медленному коду, определенно существует сильная тенденция в этом направлении. Как и в случае с большим количеством других кодов, когда вы разрабатываете библиотеки на коммерческой основе, клиенты, как правило, гораздо больше интересуются функциями, чем такими, как размер скорости.

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

Ответ 9

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

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

Существует отличный документ Ульриха Дреппера, ведущего вкладчика glibc, который описывает процесс и накладные расходы динамических библиотек.

Ответ 10

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

У меньших библиотек будет меньше проблем с любым типом компоновщика. Худший случай с небольшой библиотекой - это небольшое количество неиспользуемого кода. Многие небольшие библиотеки могут увеличить время сборки. Компромисс будет временем сборки и кодовым пространством.

Интересным тестом компоновщика является классическая программа Hello World:

#include <stdio>
#include <stdlib>
int main(void)
{
  printf("Hello World\n");
  return EXIT_SUCCESS;
}

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

Вышеуказанная программа может быть сравнена с этим с помощью puts:

#include <stdio>
#include <stdlib>
int main(void)
{
  puts("Hello World\n");
  return EXIT_SUCCESS;
}

Как правило, версия puts должна быть меньше версии printf, потому что puts не имеет требований к форматированию, поэтому меньше зависимостей. Ленивые компоновщики будут генерировать тот же размер кода, что и программа printf.

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

Ответ 11

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

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

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

Ответ 12

"другой шар и цепь". Действительно?

Или это стабильная, надежная платформа, которая позволяет ваше приложение в первую очередь?

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

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

Ответ 13

Технически, ответ заключается в том, что да, они делают. Однако эти неэффективность очень редко практически важны. Я собираюсь взять статически скомпилированный язык, такой как C, С++ или D здесь.

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

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

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

Ответ 14

Спросите себя, какова ваша цель. Это средняя рабочая станция сегодняшнего дня - не проблема. Это устаревшее оборудование или даже ограниченная встроенная система, тогда это может быть.

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

Ответ 15

fwiw, я работаю в Microsoft Windows и когда мы создаем Windows; сборка, скомпилированная для SIZE, быстрее, чем сборки, скомпилированные для SPEED, потому что вы делаете меньше обращений к ошибкам страницы.

Ответ 16

FFTW и ATLAS - две довольно большие библиотеки. Как ни странно, они играют большие роли в самом быстром программном обеспечении в мире, приложениях, оптимизированных для работы на суперкомпьютерах. Нет, использование больших библиотек не делает ваш код медленным, особенно когда альтернатива реализует процедуры FFT или BLAS для себя.

Ответ 17

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

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

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

Простое добавление в iostream добавляет к вашему коду около 3 мб (!!!). Теперь добавьте некоторую вздорную бессмыслицу, и у вас есть 30 мб кода, если вы объявите пару особенно странных структур данных.

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

  1. Сложность. Когда вы смотрите на вещи в Boost, это все, что усложняет ваш код в огромной степени. Такие вещи, как умные указатели, функторы, всевозможные сложные вещи. Теперь я не буду говорить, что никогда не рекомендуется использовать этот материал, но в значительной степени все это имеет большую стоимость. Особенно, если вы не понимаете точно, я имею в виду именно то, что он делает.

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