MSXML XSL Transformation многопоточная конкуренция за производительность - PullRequest
0 голосов
/ 28 ноября 2008

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

Это хорошо работает, но проблема в масштабируемости. При работе:

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

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

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

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

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

Ответы [ 3 ]

2 голосов
/ 28 ноября 2008

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

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

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

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

1 голос
/ 09 февраля 2009

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

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

1 голос
/ 29 ноября 2008

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

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

...