Domanda

Ho un programma C ++ server multithread che utilizza MSXML6 e analizza continuamente i messaggi XML, quindi applica una trasformazione XSLT preparata per produrre testo. Sto eseguendo questo su un server con 4 CPU. Ogni thread è completamente indipendente e utilizza il proprio oggetto di trasformazione. Non c'è condivisione di alcun oggetto COM tra i thread.

Funziona bene, ma il problema è la scalabilità. Durante l'esecuzione:

  1. con un thread, ottengo circa 26 analisi + trasformazioni al secondo per thread.
  2. con 2 thread, ottengo circa 20 / s / thread,
  3. con 3 thread, 18 / s / thread.
  4. con 4 thread, 15 / s / thread.

Con nulla condiviso tra i thread, mi aspettavo una scalabilità quasi lineare, quindi dovrebbe essere 4 volte più veloce con 4 thread rispetto a 1. Invece, è solo 2,3 volte più veloce.

Sembra un classico problema di contesa. Ho scritto programmi di test per eliminare la possibilità che la contesa sia nel mio codice. Sto usando la classe DOMDocument60 invece di quella di FreeThreadedDOMDocument per evitare blocchi inutili poiché i documenti non vengono mai condivisi tra thread. Ho cercato con forza qualsiasi prova di falsa condivisione della cache-line e non ce ne sono, almeno nel mio codice.

Un altro indizio, la frequenza di cambio di contesto è > 15k / s per ogni thread. Immagino che il colpevole sia il gestore della memoria COM o il gestore della memoria all'interno di MSXML. Forse ha un blocco globale che deve essere acquisito e rilasciato per ogni allocazione / deallocazione di memoria. Non riesco proprio a credere che al giorno d'oggi, il gestore della memoria non sia scritto in un modo che si ridimensiona bene in scenari multi-cpu multithread.

Qualcuno ha idea di cosa sta causando questa contesa o come eliminarla?

È stato utile?

Soluzione 3

Grazie per le risposte. Ho finito per implementare un mix di due suggerimenti.

Ho creato un componente COM + Serviced in C #, l'ho ospitato come un processo server separato in COM + e ho usato XSLCompiledTransform per eseguire la trasformazione. Il server C ++ si connette a questo processo esterno tramite COM e gli invia l'XML e recupera la stringa trasformata. Ciò ha raddoppiato le prestazioni.

Altri suggerimenti

È abbastanza comune per i gestori di memoria basati su heap (il tuo malloc di base / gratuito) usare un singolo mutex, ci sono abbastanza buone ragioni per farlo: un'area di memoria di heap è una singola struttura di dati coerente.

Esistono strategie alternative di gestione della memoria (ad es. allocatori gerachici) che non hanno questa limitazione. È necessario esaminare la personalizzazione dell'allocatore utilizzato da MSXML.

In alternativa, dovresti studiare il passaggio da un'architettura multi-thread a un'architettura multi-processo, con processi separati per ciascun lavoratore MSXML. Poiché il tuo lavoratore MSXML accetta i dati di stringa come input e output, non hai problemi di serializzazione.

In breve: usa un'architettura multiprocesso, si adatta meglio al tuo problema e si ridimensionerà meglio.

MSXML utilizza BSTR, che utilizzano un blocco globale nella sua gestione dell'heap. Ci ha causato molti problemi per un'app multiutente di massa qualche anno fa.

Abbiamo rimosso il nostro uso di XML nella nostra app, potresti non essere in grado di farlo, quindi potresti stare meglio usando un parser XML alternativo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top