2015-02-06 3 views
5

ich einfach folgenden Code haben:Erhalten Statistik der ausgeführten Aufgaben in C#

var tasks = statements.Select(statement => _session.ExecuteAsync(statement)); 
var result = Task.WhenAll(tasks).Result; 
[...] 

Wie kann ich berechnen min, max, avg, usw. aller ausgeführten Aufgaben? Die Aufgabenklasse hat keine Eigenschaft wie "executedMilliseconds"

+2

Dies ist nicht die Aufgabe einer Aufgabe. Was verhindert, dass Sie eine Stoppuhr verwenden, wie in [Wie lange dauert mein Code zum Ausführen?] (Http://stackoverflow.com/questions/1285052/how-long-does-my-code-take-to-run)) – CodeCaster

+0

Ich habe versucht, Stoppuhr zu verwenden, aber ich weiß nicht, wie ich jede Aufgabe messen kann. –

+1

Sie möchten also jede Aufgabe, nicht alle Aufgaben messen? Dann müssen Sie in jeder Aufgabe eine Stoppuhr implementieren. – CodeCaster

Antwort

3

Mit der folgenden Erweiterungsmethode:

public static class EnumerableExtensions 
{ 
    public static IEnumerable<Task<TimedResult<TReturn>>> TimedSelect<TSource, TReturn>(
     this IEnumerable<TSource> source, 
     Func<TSource, Task<TReturn>> func) 
    { 
     if (source == null) throw new ArgumentNullException("source"); 
     if (func == null) throw new ArgumentNullException("func"); 

     return source.Select(x => 
     { 
      Stopwatch stopwatch = new Stopwatch(); 
      stopwatch.Start(); 

      Task<TReturn> task = func(x); 

      Task<TimedResult<TReturn>> timedResultTask = task 
       .ContinueWith(y => 
       { 
        stopwatch.Stop(); 

        return new TimedResult<TReturn>(task, stopwatch.Elapsed); 
       }); 

      return timedResultTask; 
     }); 
    } 
} 

public class TimedResult<T> 
{ 
    internal TimedResult(Task<T> task, TimeSpan duration) 
    { 
     Task = task; 
     Duration = duration; 
    } 

    public readonly Task<T> Task; 
    public readonly TimeSpan Duration; 
} 

Und callsite

var tasks = statements.TimedSelect(statement => _session.ExecuteAsync(statement)); 

var result = Task.WhenAll(tasks).Result; 

können Sie die Ergebnisse extrahieren, die Sie

// Whatever works (ugly, but just as an example)... 
var min = result.Select(x => x.Duration).Min(); 
var max = result.Select(x => x.Duration).Max(); 
var avg = new TimeSpan((long)result.Select(x => x.Duration.Ticks).Average()); 

Hinweis benötigen, dass dieser Pool Wartezeit beinhaltet (Zeit, die darauf wartet, dass ein Task-Thread verfügbar wird), und ist daher möglicherweise nicht korrekt.

Eine nicht-generische Variante dieser Erweiterung ist eine Übung für den Leser.

+0

Ihre vorherige Version mit 'Timed' Methode war besser, weil sie' _session erlaubt.ExecuteAsync (Anweisung) 'ist nicht vom Typ der Elemente im Array' Anweisung' –

+0

Wenn Sie Zeile zu Funktionsdefinition zu 'öffentlichen statischen IEnumerable ändern >> TimedSelect (diese IEnumerable Quelle, Func > func)' es wird besser sein –

+0

Ich fand 'TimedSelect' besser, weil die Stoppuhr vor dem Start der Aufgabe startet. Der mit 'Timed'-Ketten nach dem Task wurde gestartet und kann zu falschen Timings führen./Bearbeiten: aktualisiert, danke. – Caramiriel

2

Sie können Aufgaben eine ContinuationTask geben, die aufgerufen wird, nachdem die Aufgabe abgeschlossen wurde. Mit diesem können Sie eine Reihe von Stoppuhren verwenden und die Fortsetzungsaufgabe verwenden, um sie einzeln zu stoppen.

+0

Wie kann ich Stoppuhr in Basis-Task und ContinuationTask teilen. –

+0

Können Sie bitte ein Codebeispiel anzeigen? –

+0

Um die Aufgaben nicht zu ändern, hätte ich eine Stoppuhr [], feuere sie alle aus und stoppe dann die n-te Stoppuhr in der n-ten Task. Jedoch. Da Task.WaitAll() keine Gewähr bietet, Ihre Tasks auf "faire" Weise zu starten, würden diese Metriken Ihnen sagen, wann die Aufgaben beendet waren, und nicht genau sagen, wie lange sie zur Ausführung benötigt haben. Im Allgemeinen sind Ausführungsthreads eine gemeinsam genutzte Ressource, so dass Sie Dinge nicht gleichzeitig fair rasen können. –