Question

J'ai un programme C ++ multithread sur serveur qui utilise MSXML6 et analyse en permanence les messages XML, puis applique une transformation XSLT préparée pour produire du texte. J'exécute ceci sur un serveur avec 4 processeurs. Chaque thread est complètement indépendant et utilise son propre objet de transformation. Il n'y a pas de partage d'objet COM entre les threads.

Cela fonctionne bien, mais le problème est l’évolutivité. Lors de l'exécution:

  1. avec un thread, je reçois environ 26 analyses + transformations par seconde par thread.
  2. avec 2 threads, je reçois environ 20 / s / thread,
  3. avec 3 threads, 18 / s / thread.
  4. avec 4 threads, 15 / s / thread.

Ne partageant rien entre les threads, je m'attendais à une évolutivité quasi-linéaire. Elle devrait donc être 4 fois plus rapide avec 4 threads qu'avec 1. Toutefois, elle n'est que 2,3 fois plus rapide.

Cela ressemble à un problème de conflit classique. J'ai écrit des programmes de test pour éliminer la possibilité que le conflit soit dans mon code. J'utilise la classe DOMDocument60 au lieu de la classe FreeThreadedDOMDocument afin d'éviter un verrouillage inutile, car les documents ne sont jamais partagés entre les threads. Je cherchais avec force toute trace de faux partage de cache-line et il n'y en a pas, du moins dans mon code.

Un autre indice, le taux de changement de contexte est > 15k / s pour chaque thread. Je suppose que le coupable est le gestionnaire de mémoire COM ou le gestionnaire de mémoire dans MSXML. Peut-être qu’il dispose d’un verrou global qui doit être acquis et libéré pour chaque allocation / désallocation de mémoire. Je ne peux tout simplement pas croire qu'aujourd'hui, le gestionnaire de mémoire n'est pas écrit de manière à évoluer dans des scénarios multithreads à plusieurs processeurs.

Quelqu'un at-il une idée de ce qui cause cette dispute ou comment l'éliminer?

Était-ce utile?

La solution 3

Merci pour les réponses. J'ai fini par mettre en œuvre un mélange des deux suggestions.

J'ai créé un ServicedComponent COM + en C #, je l'ai hébergé en tant que processus serveur distinct sous COM + et j'ai utilisé XSLCompiledTransform pour exécuter la transformation. Le serveur C ++ se connecte à ce processus externe à l'aide de COM, lui envoie le XML et récupère la chaîne transformée. Cela a doublé la performance.

Autres conseils

Il est assez courant que les gestionnaires de mémoire à base de tas (votre base malloc / free) utilisent un seul mutex, il y a d'assez bonnes raisons pour cela: une zone de mémoire est une structure de données cohérente unique.

Il existe d’autres stratégies de gestion de la mémoire (par exemple, des allocateurs hiérarchiques) qui n’ont pas cette limitation. Vous devriez étudier la possibilité de personnaliser l’allocateur utilisé par MSXML.

Sinon, vous devriez envisager de vous écarter d'une architecture multi-thread en une architecture multi-processus, avec des processus distincts pour chaque programme de traitement MSXML. Étant donné que votre assistant MSXML prend les données de chaîne en entrée et en sortie, vous n’avez pas de problème de sérialisation.

En résumé: utilisez une architecture multiprocessus, elle s’adapte mieux à votre problème et s’adapte mieux.

MSXML utilise des BSTR, qui utilisent un verrou global dans la gestion de son tas. Cela nous a causé une tonne de problèmes pour une application massivement multi-utilisateurs il y a quelques années.

Nous avons supprimé l'utilisation de XML dans notre application. Vous ne pourrez peut-être pas le faire. Vous feriez donc mieux d'utiliser un autre analyseur XML.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top