Pergunta

Eu tenho um servidor multithreaded programa C ++ que usa MSXML6 e continuamente analisa mensagens XML, em seguida, aplica uma XSLT preparado transformar em texto produtos. Estou executando isso em um servidor com 4 CPUs. Cada segmento é completamente independente e utiliza seu próprio objeto de transformar. Não há compartilhamento de quaisquer objetos COM entre as threads.

Isso funciona bem, mas o problema é a escalabilidade. Ao executar:

  1. com um fio, eu recebo cerca de 26 sintáticas + transformações por segundo por thread.
  2. com 2 fios, eu recebo cerca de 20 / s / fio,
  3. com 3 fios, 18 / s / fio.
  4. com 4 threads, 15 / s / fio.

Com nada compartilhado entre threads eu esperava escalabilidade quase linear por isso deve ser 4 vezes mais rápido com 4 threads do que com 1. Em vez disso, é de apenas 2,3 vezes mais rápidos.

Parece um problema de contenção clássico. Eu escrevi programas de teste para eliminar a possibilidade da disputa ser no meu código. Eu estou usando a classe DOMDocument60 em vez do FreeThreadedDOMDocument para evitar bloqueio desnecessário, já que os documentos nunca são compartilhados entre threads. Olhei duro para qualquer evidência de falso compartilhamento-line cache e não há qualquer, pelo menos no meu código.

Outra pista, a taxa de mudança de contexto é> 15k / s para cada segmento. Estou supondo que o culpado é o gerenciador de memória COM ou o gerenciador de memória dentro de MSXML. Talvez tenha um bloqueio global que tem de ser adquirido e liberado para cada alocação de memória / desalocação. Eu simplesmente não posso acreditar que neste dia e idade, o gerenciador de memória não está escrito de uma forma que escalas bem em cenários multi-CPU multi-tarefa.

Alguém tem alguma idéia do que está causando essa afirmação ou como eliminá-lo?

Foi útil?

Solução 3

Obrigado pelas respostas. Eu acabei implementando uma mistura das duas sugestões.

Eu fiz uma COM + ServicedComponent em C #, organizada como um processo servidor separado sob COM +, e usou o XslCompiledTransform para executar a transformação. As ++ conecta servidor C do presente processo externo usando COM e envia-o XML e recebe de volta a string transformado. Este dobrou o desempenho.

Outras dicas

É bastante comum para os gestores de memória com base em pilha (seu malloc básico / livre) para usar um único mutex, há bastante boas razões para isso:. Uma área de memória heap é uma única estrutura de dados coerente

Existem estratégias de gerenciamento de memória alternativas (por exemplo alocadores hierárquicas) que não têm essa limitação. Você deve investigar personalizar o alocador usado pelo MSXML.

Como alternativa, você deve investigar se afastando de uma arquitetura multi-threaded para uma arquitetura multi-processo, com processos separados para cada trabalhador MSXML. Desde que seus dados de cadeia trabalhador take MSXML como entrada e de saída, você não tem um problema de serialização.

Em resumo:. Utilizar uma arquitetura de multiprocessamento, é um ajuste melhor para o seu problema, e ele será ampliado melhor

MSXML usa BSTRs, que usam um bloqueio global na sua gestão heap. Isso causou-nos uma tonelada de problemas para um aplicativo maciçamente multiusuário há alguns anos.

Nós removemos o uso de XML em nossa aplicação, você pode não ser capaz de fazer isso, então você pode ser melhor fora de usar um analisador XML alternativa.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top