2010-11-12 21 views
6

Sono stato gravemente deluso e ho ricevuto un'applicazione che in determinate situazioni è almeno 100 volte troppo lenta, che devo rilasciare ai nostri clienti molto presto (poche settimane).Qualche "quick wins" per rendere il servizio di remoting .NET più veloce su una singola macchina?

Attraverso alcuni molto semplici profiling ho scoperto che il collo di bottiglia è il suo uso di .NET Remoting per trasferire dati tra un servizio di Windows e il front-end grafico - sia in esecuzione sulla stessa macchina.

Microsoft guidelines dire "Minimizzare viaggi di andata e di evitare le interfacce chiacchierone": scrivere

MyComponent.SaveCustomer("bob", "smith"); 

piuttosto che

MyComponent.Firstname = "bob"; 
MyComponent.LastName = "smith"; 
MyComponent.SaveCustomer(); 

Penso che questa è la radice del problema nella nostra applicazione. Sfortunatamente le chiamate a MyComponent. * (Il profiler mostra che il 99,999% del tempo è trascorso in tali dichiarazioni) sono disseminate liberamente nel codice sorgente e non vedo alcuna speranza di ridisegnare l'interfaccia in conformità con le linee guida precedenti.

Modifica: In realtà, il più delle volte il front-end legge proprietà di MyComponent anziché scrivere su di esso. Ma sospetto che MyComponent possa cambiare in qualsiasi momento nel back-end.

Ho cercato di vedere se sono in grado di leggere tutte le proprietà da MyComponent in una volta sola e di memorizzarle in cache localmente (ignorando il problema di modifica in qualsiasi momento sopra), ma ciò comporterebbe la modifica di centinaia di righe di codice.

La mia domanda è: sono qualche cosa 'vincente in fretta' che posso provare a migliorare le prestazioni?

Ho bisogno di almeno 100 volte di accelerare. Sono un programmatore C/C++/Delphi e sono piuttosto poco pratico con C# /. NET/Remoting diverso da quello che ho letto negli ultimi due giorni. Sto cercando cose che possono essere completate in pochi giorni - una ristrutturazione importante del codice non è un'opzione.

Solo per i principianti, ho già confermato che sta utilizzando BinaryFormatter.

(Siamo spiacenti, questo è probabilmente una domanda terribile sulla falsariga di 'Come posso tenerne correzione X se io escludo tutte le opzioni possibili' ... ma io sono disperato!)

Edit 2 In risposta al commento di Richard di seguito: credo che la mia domanda si riduce a:

  1. c'è qualche impostazione che posso cambiare per ridurre il costo di un .NET Remoting di andata e ritorno, quando entrambe le estremità della connessione sono sul stessa macchina?
  2. Esiste qualche impostazione che posso modificare per ridurre il numero di round-trip, in modo che ogni richiamo di una proprietà dell'oggetto remoto non determini un round-trip separato? E questo potrebbe rompere qualcosa?
+1

È probabile che le opzioni siano limitate, .NET Remoting è fortemente deprecato (tranne che per Inter-AppDomain) a causa della sua mancanza di sicurezza. – Richard

+1

"Quick win" invariabile significa "lento perdere" imho, sii molto diffidente nei confronti di quella frase. – annakata

+0

Se si trattava di WCF, il ["trasporto nullo"] (http://www.codeproject.com/KB/WCF/NullTransportForWCF.aspx) avrebbe potuto essere d'aiuto, ma si tratta di un modello molto diverso rispetto alla comunicazione remota. –

risposta

7

Sotto .Net Remoting ci sono 3 modi di comunicare tramite HTTP, TCP e IPC. Se il commnuicatin si trova sullo stesso PC, mi piace utilizzare i canali IPC per accelerare le chiamate.

+1

Grazie! Questo è esattamente il tipo di risposta che speravo. Si scopre che stava usando HTTP. Un'operazione che ha richiesto 3 minuti e 20 secondi con HTTP ha richiesto 1 minuto 24 con TCP e 59 secondi con IPC. 59 secondi è ancora piuttosto lungo (dal punto di vista dell'utente, è sufficiente espandere un nodo su una vista ad albero in modo che dovrebbe essere istantaneo) ma è un grande miglioramento. Per il beneficio di chiunque altro provi questo, ho dovuto specificare authorizedGroup = "Users" nell'elemento sul server. Altrimenti è stato semplice. –

+0

Sto facendo di questa mia "risposta accettata" perché è un vero successo. Devo comunque accelerare ulteriormente il codice. –

1

È possibile provare a comprimere il traffico. Se non aumenti di 100 volte, otterrai comunque qualche vantaggio in termini di prestazioni

+0

Mentre posso vedere che è un vantaggio quando i dati vengono trasferiti attraverso una rete, nel mio caso non si aggiungeranno solo al carico di elaborazione? La CPU è già cavigliata vicino al 100%. –

+1

@Ian - in questo caso sembra che i viaggi di andata e ritorno siano il problema più probabile; la compressione del traffico aiuta * la larghezza di banda *, ma non aiuta * la latenza *. –

3

Potresti rendere MyComponent una classe che memorizzerà i valori nella cache e li invierà solo quando viene richiamato SaveCustomer()?

+0

Avrei dovuto essere più chiaro nella mia domanda iniziale: il più delle volte il front-end sembra leggere dall'oggetto remoto, non scriverci sopra. Ma sospetto che l'oggetto remoto possa cambiare in qualsiasi momento, quindi il caching nel front-end potrebbe non essere un'opzione. –

+0

@IanGoldby: se non riesci a ridurre i viaggi di andata e ritorno della rete, o il costo di ogni round trip, sei bloccato. Dovrai scendere a compromessi (o usare la magia). – Richard

+0

Se l'oggetto viene richiesto molto, si può ancora prendere in considerazione la memorizzazione nella cache, anche se è solo per pochi secondi. Dipende davvero da quanto spesso il cliente richiede i dati e quanto sia critico. In bocca al lupo! – flayn

1

Se sono necessari i dati più recenti (vedere sempre il valore reale) e il costo di ottenere i dati ogni volta domina il runtime, è necessario essere radicali.

Come cambiare il polling da premere. Piuttosto che chiamare il lato remoto ogni volta che è necessario un valore, fare in modo che il telecomando spinga tutte le modifiche e memorizzi in cache gli ultimi valori localmente.

Le ricerche locali (dopo l'avvio iniziale) sono sempre aggiornate con tutto il sovraccarico remoto eseguito in background (su un altro thread). Basta fare attenzione alla sicurezza dei thread per i tipi non atomici.

5

In breve, non ci sono vittorie veloci qui. Personalmente vorrei non fare MyComponent (come DTO) uno MarshalByRefObject (che è presumibilmente il problema), come quei viaggi di andata stanno per paralizzarti. Lo terrei come una classe normale e sposterei solo alcuni metodi chiave per pomparli (ad esempio, una classe MarshalByRefmanager/repository/etc).

Che dovrebbe ridurre round-trip; se hai ancora hai problemi allora sarà probabilmente larghezza di banda correlata; questo è più facile da risolvere; ad esempio cambiando il serializzatore. protobuf-net ti permette di farlo facilmente semplicemente implementando ISerializable e inoltrando i due metodi (uno dall'interfaccia, più il ctor) a ProtoBuf.Serializer - allora fa tutto il lavoro per te, e funziona con i servizi remoti. Posso fornire esempi di questo se ti piace.

In realtà, protobuf-net può aiutare anche con l'utilizzo della CPU, in quanto è un serializzatore molto più efficiente della CPU.