MSXML XSL Transformation Конкуренция за многопоточную производительность

У меня есть многопоточная серверная программа C++, которая использует MSXML6 и непрерывно анализирует сообщения XML, а затем применяет подготовленное преобразование XSLT для создания текста. Я запускаю это на сервере с 4 процессорами. Каждый поток полностью независим и использует свой собственный объект преобразования. Между потоками нет совместного использования каких-либо COM-объектов.

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

  1. с одним потоком я получаю около 26 синтаксических анализов + преобразований в секунду на поток.
  2. с 2 потоками я получаю около 20/с/поток,
  3. с 3 нитями, 18/с/резьба.
  4. с 4 нитями, 15/с/резьба.

Поскольку между потоками не было ничего общего, я ожидал почти линейной масштабируемости, поэтому он должен быть в 4 раза быстрее с 4 потоками, чем с 1. Вместо этого он всего в 2,3 раза быстрее.

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

Еще одна подсказка: скорость переключения контекста > 15 к/с для каждого потока. Я предполагаю, что виновником является диспетчер памяти COM или диспетчер памяти в MSXML. Возможно, у него есть глобальная блокировка, которую необходимо получить и снять при каждом выделении/освобождении памяти. Я просто не могу поверить, что в наши дни диспетчер памяти не написан таким образом, чтобы хорошо масштабироваться в многопоточных многопроцессорных сценариях.

Кто-нибудь знает, что вызывает это утверждение или как его устранить?


person Carlos A. Ibarra    schedule 28.11.2008    source источник


Ответы (3)


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

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

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

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

person ddaa    schedule 28.11.2008

MSXML использует BSTR, которые используют глобальную блокировку при управлении кучей. Несколько лет назад это вызвало у нас массу проблем с массовым многопользовательским приложением.

Мы удалили использование XML в нашем приложении, возможно, вы не сможете этого сделать, поэтому вам лучше использовать альтернативный анализатор XML.

person gbjbaanb    schedule 29.11.2008

Спасибо за ответы. В итоге я реализовал сочетание двух предложений.

Я создал COM+ ServicedComponent на C#, разместил его как отдельный серверный процесс в COM+ и использовал XSLCompiledTransform для выполнения преобразования. Сервер C++ подключается к этому внешнему процессу с помощью COM, отправляет ему XML и возвращает преобразованную строку. Это удвоило производительность.

person Carlos A. Ibarra    schedule 09.02.2009