Это может звучать странно, но в моем отделе у нас возникают проблемы со следующей ситуацией:
Мы работаем здесь над серверным приложением, которое становится все больше и больше, даже в тот момент, когда мы рассматриваем его разделение на разные части (файлы DLL), динамическую загрузку при необходимости и последующую выгрузку, чтобы иметь возможность обрабатывать проблемы с производительностью.
Но: функции, которые мы используем, передают входной и выходной параметры как объекты STL, и, как упоминалось в ответе на переполнение стека , это очень плохая идея. (Пост содержит некоторые ± решения и взломы, но все это выглядит не очень солидно.)
Очевидно, что мы могли бы заменить параметры ввода / вывода стандартными типами C ++ и создать объекты STL из тех, которые когда-то были внутри функций, но это может привести к падению производительности.
Можно ли сделать вывод, что, если вы планируете создать приложение, которое может вырасти настолько большим, что один ПК больше не сможет с ним работать, вы вообще не должны использовать STL в качестве технологии?
Дополнительные сведения об этом вопросе.
Похоже, есть некоторые недоразумения по этому вопросу: проблема заключается в следующем:
мое приложение использует огромный объем производительности (ЦП, память) для завершения своей работы, и я хотел бы разделить эту работу на разные части (так как программа уже разбита на несколько функций), не так сложно создать некоторые библиотеки DLL из моего приложения и поместить некоторые функции в таблицу экспорта этих библиотек DLL. Это приведет к следующей ситуации:
+-----------+-----------+----
| Machine1 | Machine2 | ...
| App_Inst1 | App_Inst2 | ...
| | |
| DLL1.1 | DLL2.1 | ...
| DLL1.2 | DLL2.2 | ...
| DLL1.x | DLL2.x | ...
+-----------+-----------+----
App_Inst1 - это экземпляр приложения, установленного на Machine1, а App_Inst2 - это экземпляр того же приложения, установленного на Machine2.
DLL1.x - это DLL, установленная на Machine1, а DLL2.x - это DLL, установленная на Machine2.
DLLx.1 охватывает экспортируемую функцию1.
DLLx.2 покрывает экспортируемую функцию2.
Теперь на Machine1 я бы хотел выполнить function1 и function2. Я знаю, что это перегрузит Machine1, поэтому я хотел бы отправить сообщение в App_Inst2 с просьбой, чтобы этот экземпляр приложения выполнил function2.
Параметры ввода / вывода для function1 и function2 являются объектами STL (стандартная библиотека типов C ++), и регулярно я могу ожидать, что клиент будет обновлять App_Inst1, App_Inst2, DLLx.y (но не все из них, клиент может обновить Machine1, но не Machine2, или только обновить приложения, но не библиотеки DLL или наоборот, ...). Очевидно, что если интерфейс (параметры ввода / вывода) изменится, то клиент вынужден выполнить полную модернизацию.
Однако, как упомянуто в упомянутом URL-адресе StackOverflow, простая повторная компиляция App_Inst1 или одной из библиотек DLL может привести к развалу всей системы, поэтому мой первоначальный заголовок этого поста не рекомендует использовать STL (стандартный шаблон C ++ Библиотека) для больших приложений.
Я надеюсь, что этим я прояснил некоторые вопросы / сомнения.
Ответы:
Это классическая проблема XY.
Ваша настоящая проблема - это проблемы с производительностью. Однако ваш вопрос проясняет, что вы не проводили профилирование или другие оценки того, откуда на самом деле возникают проблемы с производительностью. Вместо этого вы надеетесь, что разбиение вашего кода на библиотеки DLL волшебным образом решит проблему (чего, к сожалению, не будет), и теперь вы беспокоитесь об одном аспекте этого решения.
Вместо этого вам нужно решить реальную проблему. Если у вас есть несколько исполняемых файлов, проверьте, какой из них вызывает замедление. Пока вы это делаете, убедитесь, что на самом деле ваша программа занимает все время обработки, а не плохо настроенный драйвер Ethernet или что-то в этом роде. И после этого начните профилировать различные задачи в вашем коде. Высокоточный таймер - ваш друг здесь. Классическим решением является мониторинг среднего и наихудшего времени обработки фрагмента кода.
Когда у вас есть данные, вы можете решить, как справиться с проблемой, а затем вы можете решить, где оптимизировать.
источник
Если вам нужно разделить программное обеспечение между несколькими физическими машинами, вам придется иметь некоторую форму сериализации при передаче данных между машинами, поскольку только в некоторых случаях вы можете просто отправить один и тот же точный двоичный файл между машинами. У большинства методов сериализации нет проблем с обработкой типов STL, поэтому этот случай меня не беспокоит.
Если вам нужно разделить приложение на общие библиотеки (DLL) (прежде чем делать это по соображениям производительности, вам действительно следует убедиться, что это действительно решит ваши проблемы с производительностью), передача объектов STL может быть проблемой, но это не обязательно. Как вы уже указали по ссылке, передача объектов STL работает, если вы используете тот же компилятор и те же настройки компилятора. Если пользователи предоставляют библиотеки DLL, вы не сможете легко рассчитывать на это. Однако, если вы предоставите все библиотеки DLL и скомпилируете все вместе, тогда вы сможете рассчитывать на это, и использование объектов STL через границы DLL станет очень возможным. Вам все еще нужно следить за настройками компилятора, чтобы не получить несколько разных куч, если вы передаете владение объектом, хотя это не является специфической проблемой STL.
источник
Оперативная память дешева, и поэтому неактивный код дешев. Загрузка и выгрузка кода (особенно выгрузка) - это хрупкий процесс, который вряд ли существенно повлияет на производительность ваших программ на современном настольном / серверном оборудовании.
Кэш дороже, но это влияет только на код, который недавно активен, а не код, который находится в памяти неиспользованным.
В общем случае программы перерастают свои компьютеры из-за размера данных или времени процессора, а не размера кода. Если размер вашего кода становится настолько большим, что он вызывает серьезные проблемы, вы, вероятно, захотите узнать, почему это происходит в первую очередь.
Все должно быть в порядке, если dll и исполняемый файл все собраны с одним и тем же компилятором и динамически связаны с одной и той же библиотекой времени выполнения C ++. Из этого следует, что если приложение и связанные с ним библиотеки создаются и развертываются как единое целое, то это не должно быть проблемой.
Проблема может возникнуть, когда библиотеки создаются разными людьми или могут обновляться отдельно.
На самом деле, нет.
Как только вы начнете распределять приложение по нескольким машинам, у вас будет масса соображений относительно того, как вы передаете данные между этими машинами. Детали того, используются ли типы STL или более базовых типов, вероятно, будут потеряны в шуме.
источник
Нет, я не думаю, что этот вывод следует. Даже если ваша программа распределена по нескольким машинам, нет никаких причин, по которым использование STL внутренне вынуждает вас использовать ее для взаимодействия между модулями / процессами.
На самом деле, я бы сказал, что вы должны отделять дизайн внешних интерфейсов от внутренней реализации с самого начала, так как первый будет более твердым / трудным для изменения по сравнению с тем, что используется внутри.
источник
Вы упускаете суть этого вопроса.
Есть в основном два типа DLL. Ваш и чужой. «Проблема STL» заключается в том, что вы и они, возможно, не используете один и тот же компилятор. Очевидно, что это не проблема для вашей собственной DLL.
источник
Если вы создаете библиотеки DLL из одного и того же дерева исходных текстов одновременно с одним и тем же компилятором и параметрами сборки, то все будет работать нормально.
Однако «приправленный Windows» способ разбить приложение на несколько частей, некоторые из которых можно использовать повторно, это COM-компоненты . Они могут быть маленькими (отдельные элементы управления или кодеки) или большими (IE доступен как элемент управления COM, в mshtml.dll).
Для серверного приложения это, вероятно, будет иметь ужасную эффективность; это действительно реально, только если у вас есть приложение, которое проходит через несколько этапов в течение длительного периода времени, чтобы вы знали, когда что-то больше не понадобится. Это напоминает мне игры DOS, использующие механизм наложения.
Кроме того, если ваша система виртуальной памяти работает должным образом, она справится с этим за счет перемещения неиспользуемых кодовых страниц.
Купите большой компьютер.
Не забывайте, что при правильной оптимизации ноутбук может превзойти кластер Hadoop.
Если вам действительно нужно несколько систем, вы должны очень тщательно продумать границу между ними, поскольку именно здесь и стоит стоимость сериализации. Это где вы должны начать смотреть на фреймворки, такие как MPI.
источник
Первая часть имеет смысл (разделение приложения на разные машины по соображениям производительности).
Вторая часть (загрузка и выгрузка библиотек) не имеет смысла, так как это требует дополнительных усилий, и она (действительно) не улучшит ситуацию.
Проблема, которую вы описываете, лучше решается с помощью специализированных вычислительных машин, но они не должны работать с одним и тем же (основным) приложением.
Классическое решение выглядит так:
Между интерфейсными и вычислительными машинами могут быть дополнительные функции, такие как балансировка нагрузки и мониторинг производительности, а поддержка специализированной обработки на выделенных машинах хороша для оптимизации кэширования и пропускной способности.
Это никоим образом не подразумевает дополнительную загрузку / выгрузку DLL, а также не имеет ничего общего с STL.
То есть используйте STL по мере необходимости и сериализуйте ваши данные между элементами (см. Grpc и буферы протокола и вид проблем, которые они решают).
Тем не менее, с учетом предоставленной вами ограниченной информации, это похоже на классическую проблему xy (как сказал @Graham).
источник