2013-03-13 15 views
9

Sto scrivendo una classe di utilità molto semplice con lo scopo di misurare il tempo eseguito per qualsiasi metodo passato (di qualsiasi tipo).Come contare il tempo trascorso per un metodo con una classe di utilità

Nel mio caso Membership.ValidateUser(model.UserName, model.Password) return bool quindi ottengo un'eccezione.

Vorrei se fosse possibile scrivere una classe di utilità di questo tipo e un esempio di codice su come risolverlo. Ha senso utilizzare dinamicamente al posto dell'azione?

Tracing.Log(Membership.ValidateUser(model.UserName, model.Password), "Membership.ValidateUser"); 

public static class Tracing 
     { 
      public static void Log(Action action, string message) 
      { 
       // Default details for the Log 
       string sSource = "TRACE"; 
       string sLog = "Application"; 

       // Create the Log 
       if (!EventLog.SourceExists(sSource)) 
        EventLog.CreateEventSource(sSource, sLog); 

       // Measure time Elapsed for an Action 
       Stopwatch stopwatch = Stopwatch.StartNew(); 
       action(); 
       stopwatch.Stop(); 
       TimeSpan timeElapsed = stopwatch.Elapsed; 

       // Write the Log 
       EventLog.WriteEntry(sSource, "TIME-ELAPSED: " + timeElapsed .ToString() + message, EventLogEntryType.Warning, 234); 
      } 
     } 

risposta

8

il codice corrente cerca di eseguire ValidateUser e utilizzare il risultato come argomento metodo. Si desidera passare un'azione senza prima esecuzione ValidateUser.

Hai solo bisogno di convertire la chiamata metodo da utilizzare un'espressione lambda per creare un delegato: (. Tipizzazione dinamica non inciderebbe questo a tutti)

Tracing.Log(() => Membership.ValidateUser(model.UserName, model.Password), 
      "Membership.ValidateUser"); 

Si noti che una singola temporizzazione l'esecuzione del metodo spesso ti dà risultati molto rumorosi, a meno che non si tratti di una chiamata al metodo ragionevolmente lunga. Solitamente per eseguire il benchmark di un singolo metodo, si desidera eseguire il metodo molte volte, finché non si è trascorso un tempo ragionevolmente significativo per eseguirlo. L'utilizzo di Stopwatch aiuta, ma non va oltre il fatto che il tuo metodo potrebbe richiedere pochissime zecche per essere completato, e se il thread è anticipato, questo avrà un effetto sproporzionato sui risultati.

EDIT: Presumo che tu voglia utilizzare questo solo per il benchmarking. Se stai cercando di eseguire questa traccia nella tua vera applicazione, ti consigliamo un approccio meno invasivo. Guarda Mini-MVC-Profiler per esempio.

+0

Desidero ringraziare il vostro per la vostra spiegazione. Come potrebbe riscrivere la mia classe e far entrare l'uso di labda? grazie per il tuo tempo – GibboK

+0

@GibboK: non so cosa intendi. Ti ho mostrato come puoi chiamare il metodo. –

+0

Grazie Jon, non ero a conoscenza di MVC-Profiler. – GibboK

0

Nessun reato inteso, ma il tuo approccio progettuale mi sembra al contrario. Presumo che i tuoi obiettivi di business siano più relativi alla convalida di un utente rispetto alle operazioni del codice di temporizzazione. Se ciò non è corretto, ignorami. :)

Se fossi in te, inietterei una classe di cronometraggio/tracciamento nella convalida anziché viceversa. È possibile utilizzare l'integrazione delle dipendenze in vari modi (uno dei framework o un'iniezione semplice del costruttore) e utilizzarlo per eseguire il cronometro se è stato fornito.

HTH

+1

Anche se va bene tracciare il traffico in tempo reale, è * anche * utile essere in grado di esercitare un metodo esclusivamente per il benchmarking. –

+0

Sì, ho solo bisogno di un modo rapido per tracciare il traffico in tempo reale – GibboK

+0

Nessun argomento, ma non capisco perché si possa scaricare la responsabilità di eseguire un'azione o Func (cosa è successo al desiderio dell'OP di riavere il bool?) A un classe di aiuto. Che cosa succede se, ad esempio, si desidera utilizzare la classe helper _another_ progettata allo stesso modo per fornire le metriche di profilazione? ValidateUser ha già eseguito la chiamata precedente .. IDK .. –

0

Se è possibile modificare il metodo che viene misurata, è possibile introdurre una classe che avrà inizio il timer a sua creazione, e fermarlo sullo smaltimento. E, se una certa soglia viene superata, si creerà un messaggio di log

Uso sarà:

using(var tm = new TimeMeasurementThreshold(TimeSpan.FromSeconds(1),"Sending mail block",logger)){ 
// measured code here 
} 

public class TimeMeasurementThreshold : IDisposable 
    { 
     private readonly Logger logger; 

     private readonly TimeSpan thresholdTime; 

     private readonly string codeBlockName; 

     private readonly TimeMeasurement timeMeasurement; 

     public TimeMeasurementThreshold(TimeSpan thresholdTime, string codeBlockName, Logger logger) 
     { 
      this.logger = logger; 
      this.thresholdTime = thresholdTime; 
      this.codeBlockName = codeBlockName; 

      timeMeasurement = new TimeMeasurement(); 
     } 

     public void Dispose() 
     { 
      TimeSpan elapsed = timeMeasurement.Elapsed; 

      if (elapsed >= thresholdTime) 
      { 
       logger.Debug("{0} execution time is {1:N0}ms", codeBlockName, elapsed.TotalMilliseconds); 
      } 
     } 
    } 
0

Si può facilmente utilizzare un lambda per assegnare il risultato di un'azione che si passa a un altro metodo, per esempio:

using System; 

namespace Demo 
{ 
    public static class Program 
    { 
     private static void Main(string[] args) 
     { 
      bool result = false; 

      Tracing.Log(() => 
      { 
       result = test(""); // Assign to result. 
      }, "Message"); 

      Console.WriteLine(result); 
     } 

     private static bool test(string value) 
     { 
      return string.IsNullOrEmpty(value); 
     } 
    } 

    public static class Tracing 
    { 
     public static void Log(Action action, string message) 
     { 
      action(); 
      Console.WriteLine(message); 
     } 
    } 
} 
Problemi correlati