Pregunta

Tengo un programa C ++ de servidor multiproceso que usa MSXML6 y analiza continuamente los mensajes XML, luego aplica una transformación XSLT preparada para producir texto. Estoy ejecutando esto en un servidor con 4 CPU. Cada subproceso es completamente independiente y utiliza su propio objeto de transformación. No se comparten objetos COM entre los hilos.

Esto funciona bien, pero el problema es la escalabilidad. Cuando se ejecuta:

  1. con un hilo, obtengo alrededor de 26 transformaciones + análisis por segundo por hilo.
  2. con 2 hilos, obtengo aproximadamente 20 / s / hilo,
  3. con 3 hilos, 18 / s / hilo.
  4. con 4 hilos, 15 / s / hilo.

Sin nada compartido entre los subprocesos, esperaba una escalabilidad casi lineal, por lo que debería ser 4 veces más rápido con 4 subprocesos que con 1. En cambio, es solo 2.3 veces más rápido.

Parece un problema de contención clásico. He escrito programas de prueba para eliminar la posibilidad de que la disputa esté en mi código. Estoy usando la clase DOMDocument60 en lugar de la clase FreeThreadedDOMDocument para evitar bloqueos innecesarios ya que los documentos nunca se comparten entre subprocesos. Busqué cualquier evidencia de intercambio falso de línea de caché y no hay ninguna, al menos en mi código.

Otra pista, la velocidad de cambio de contexto es > 15k / s para cada hilo. Supongo que el culpable es el administrador de memoria COM o el administrador de memoria dentro de MSXML. Tal vez tiene un bloqueo global que debe adquirirse y liberarse para cada asignación / desasignación de memoria. Simplemente no puedo creer que hoy en día, el administrador de memoria no esté escrito de una manera que se adapte bien en escenarios multiproceso de múltiples CPU.

¿Alguien tiene alguna idea de qué está causando esta disputa o cómo eliminarla?

¿Fue útil?

Solución 3

Gracias por las respuestas. Terminé implementando una mezcla de las dos sugerencias.

Creé un COM + ServicedComponent en C #, lo alojé como un proceso de servidor separado en COM +, y usé XSLCompiledTransform para ejecutar la transformación. El servidor C ++ se conecta a este proceso externo mediante COM y le envía el XML y recupera la cadena transformada. Esto duplicó el rendimiento.

Otros consejos

Es bastante común que los administradores de memoria basados ??en el montón (su malloc básico / libre) utilicen un único mutex, hay razones bastante buenas para ello: un área de memoria del montón es una única estructura de datos coherente.

Existen estrategias alternativas de administración de memoria (por ejemplo, asignadores jerárquicos) que no tienen esta limitación. Debe investigar la personalización del asignador utilizado por MSXML.

Alternativamente, debe investigar alejarse de una arquitectura multiproceso a una arquitectura multiproceso, con procesos separados para cada trabajador MSXML. Como su trabajador MSXML toma datos de cadena como entrada y salida, no tiene un problema de serialización.

En resumen: use una arquitectura multiproceso, se adapta mejor a su problema y se escalará mejor.

MSXML utiliza BSTR, que utilizan un bloqueo global en su gestión de almacenamiento dinámico. Nos causó muchos problemas para una aplicación multiusuario masiva hace unos años.

Eliminamos nuestro uso de XML en nuestra aplicación, es posible que no pueda hacerlo, por lo que es mejor que utilice un analizador XML alternativo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top