Domanda

Sto profilando un programma multithread in esecuzione con un numero diverso di thread consentiti. Di seguito sono riportati i risultati delle prestazioni di tre esecuzioni dello stesso lavoro di input.

1 thread:
  Total thread time: 60 minutes.
  Total wall clock time: 60 minutes.

10 threads:
  Total thread time: 80 minutes. (Worked 33% longer)
  Total wall clock time: 18 minutes.  3.3 times speed up

20 threads
  Total thread time: 120 minutes. (Worked 100% longer)
  Total wall clock time: 12 minutes.  5 times speed up

Poiché ci vuole più tempo del thread per fare lo stesso lavoro, ritengo che i thread debbano lottare per le risorse.

Ho già esaminato i quattro pilastri (cpu, memoria, diskIO, rete) sia sul computer dell'app che sul server del database. La memoria era la risorsa originale contesa, ma ora è stato risolto (più di 1G gratuito in ogni momento). La CPU oscilla tra il 30% e il 70% nel test a 20 thread, quindi ce n'è in abbondanza. diskIO è praticamente nessuno sul computer dell'app e minimo sul server del database. La rete è davvero eccezionale.

Ho anche profilato il codice con redgate e non vedo metodi in attesa di blocchi. Aiuta il fatto che i thread non condividano le istanze. Ora sto controllando elementi più sfumati come stabilire / raggruppare la connessione al database (se 20 thread tentano di connettersi allo stesso database, devono aspettarsi a vicenda?).

Sto cercando di identificare e risolvere il conflitto di risorse, in modo che l'esecuzione di 20 thread sia simile a questa:

20 threads
  Total thread time: 60 minutes. (Worked 0% longer)
  Total wall clock time: 6 minutes.  10 times speed up

Quali sono le fonti più probabili (oltre ai 4 grandi) che dovrei esaminare per trovare tale contesa?


Il codice eseguito da ogni thread è approssimativamente:

Run ~50 compiled LinqToSql queries
Run ILOG Rules
Call WCF Service which runs ~50 compiled LinqToSql queries, returns some data
Run more ILOG Rules
Call another WCF service which uses devexpress to render a pdf, returns as binary data
Store pdf to network
Use LinqToSql to update/insert. DTC is involved: multiple databases, one server.

I servizi WCF sono in esecuzione sulla stessa macchina e sono senza stato e in grado di gestire più richieste simultanee.


La macchina ha 8 CPU.

È stato utile?

Soluzione

Quello che descrivi è che vuoi una scalabilità del 100% che sia una relazione 1: 1 tra l'aumento dei thread se la diminuzione del tempo di wallcklock ... questo è solitamente un obiettivo ma difficile da raggiungere ...

Ad esempio scrivi che non c'è conflitto di memoria perché c'è 1 GB libero ... questo è IMHO un presupposto sbagliato ... conflitto di memoria significa anche che se due thread provano ad allocare memoria potrebbe accadere che uno debba aspetta l'altro ... un altro ponint da tenere a mente sono le interruzioni che avvengono da GC che blocca temporaneamente tutti i thread ... il GC può essere personalizzato un po 'tramite configurazione (gcServer) - vedi http://blogs.msdn.com/b/clyon/archive/2004/09/08 /226981.aspx

Un altro punto è il servizio WCF chiamato ... se non è in grado di aumentare la scalabilità, ad esempio il rendering PDF, è anche una forma di contesa, ad esempio ...

L'elenco delle possibili contese è "infinito" ... e difficilmente sempre nelle aree ovvie che hai menzionato ...

MODIFICA - come da commenti:

Alcuni punti da verificare:

  • pool di connessioni
    quale provider usi? come è configurato?
  • Rendering PDF
    possibile contesa sarebbe misurata da qualche parte all'interno della libreria che usi ...
  • Linq2SQL
    Controlla i piani di esecuzione per tutte queste query ... può essere che alcuni prendano qualsiasi tipo di blocco e quindi creino una contesa lato server DB ...

MODIFICA 2:

Thread
Questi thread provengono da ThreadPool? Se è così, non scalerai :-(

MODIFICA 3:

I thread ThreadPool sono dannosi per le attività a lunga esecuzione, come nel tuo scenario ... per i dettagli vedi

Da http://www.yoda.arachsys.com/csharp/ thread / printable.shtml

Le operazioni a esecuzione prolungata dovrebbero utilizzare thread appena creati; le operazioni di breve durata possono trarre vantaggio dal pool di thread.

Se desideri prestazioni estreme, potrebbe valere la pena dare un'occhiata a CQRS e al real- esempio mondiale descritto come LMAX .

Altri suggerimenti

Invece di misurare il tempo totale del thread, misura il tempo per ciascuna delle operazioni che esegui che eseguono I / O di qualche tipo (database, disco, rete, ecc.).

Sospetto che scoprirai che queste operazioni sono quelle che richiedono più tempo quando hai più thread, e questo perché la contesa è dall'altra parte di quell'I / O.Ad esempio, il database potrebbe serializzare le richieste di coerenza dei dati.

sì, c'è una contesa sulle risorse. Tutti i thread devono leggere / scrivere dati sullo stesso bus di memoria, ad esempio diretti agli stessi moduli RAM. Non importa quanta RAM sia libera, importa che le letture / scritture siano eseguite dallo stesso controller di memoria sugli stessi moduli RAM e che i dati siano trasportati sullo stesso bus.

Se esiste un qualsiasi tipo di sincronizzazione ovunque , anche quella è una risorsa contesa. Se c'è qualsiasi I / O, questa è una risorsa contesa.

Non vedrai mai una velocità di N x quando passi da 1 a N thread. Non è possibile perché alla fine, tutto nella CPU è una risorsa condivisa su cui ci sarà un certo grado di contesa.

Ci sono molti fattori che ti impediscono di ottenere la piena velocità lineare. Stai assumendo che il database, il server su cui è in esecuzione il database, la rete che lo connette al client, il computer client, il sistema operativo e i driver su entrambe le estremità, il sottosistema di memoria, l'I / O del disco e tutto in between è in grado di andare solo 20 volte più veloce quando passi da 1 a 20 thread.

Due parole: continua a sognare.

Ognuno di questi colli di bottiglia deve rallentarti solo di una piccola percentuale, quindi il risultato complessivo sarà qualcosa di simile a quello che stai vedendo.

Sono sicuro che puoi modificarlo per ridimensionarlo un po 'meglio, ma non aspettarti miracoli.

Ma una cosa che potresti cercare è la condivisione della linea della cache. I thread accedono a dati molto vicini ai dati utilizzati da altri thread? Con che frequenza puoi evitare che ciò accada?

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