2016-05-25 8 views
0

Ich habe eine Anwendung, die derzeit Aufgaben in einem Zeitintervall, aber ich möchte mehr Kontrolle darüber, in der Lage sein, eine laufende Aufgabe zu stoppen und neu zu starten durch Klicken auf eine Benutzeroberfläche.Verwaltung von Task.Run und stop/cancel der Methode und erhalten Fortschritt

Es gibt im Moment 6 Aufgaben, aber ich möchte die Dinge allgemein halten, um bei Bedarf einfach mehr zu können. Ich hatte gehofft, einen Wrapper erstellen zu können, mit dem ich eine Methode als Parameter übergeben kann.

Als solche habe ich ein Objekt, das ich so viele erstellen, wie es Aufgaben gibt, kann ich Status-Updates von ihm sowie verwalten es

Ich möchte bekommen: - Starten Sie eine Methode/Aufgaben Stoppen sie eine Methode/Aufgaben - - Starten sie eine Methode/Aufgaben - Holen sie sich Feedback von ihr Logbuch/Aktuelles/progress/Fehler, die ich auf Updates Liste aufnehmen

ist dies ein guter Weg, dies zu tun, gibt es eine bessere Art und Weise um zu erreichen, wonach ich suche?

public class ManagedTask 
    { 
     public ManagedTask() 
     { 
      CreateNewToken(); 
     } 

     public int Id { get; set; } 
     public string DescriptiveName { get; set; } 
     public Action<CancellationToken> TheVoidToRun { private get; set; } 
     private CancellationTokenSource CTokenSource { get; set; } 
     private CancellationToken CToken { get; set; } 
     private Task TheRunningThing { get; set; } 

     public void StartIt() 
     { 
      if (TheRunningThing == null || TheTaskStatus() == TaskStatus.Canceled || TheTaskStatus() == TaskStatus.RanToCompletion) 
      { 
       CreateNewToken(); 
      } 
      // Start up the Task 
      AddUpdate($"Starting Task at {DateTime.Now}"); 
      TheRunningThing = Task.Run(() => TheVoidToRun?.Invoke(CToken), CToken); 
      AddUpdate($"Started Task at {DateTime.Now}"); 
     } 
     public void EndIt() 
     { 
      AddUpdate($"Cancelling Task at {DateTime.Now}"); 
      CTokenSource.Cancel(); 
      // Do - If in progress try to stop (Cancellation Token) 
      // Do - Stop future repeats 
     } 

     private void CreateNewToken() 
     { 
      CTokenSource = new CancellationTokenSource(); 
      CTokenSource.Token.ThrowIfCancellationRequested(); 
      CToken = CTokenSource.Token; 
     } 

     public TaskStatus TheTaskStatus() => TheRunningThing.Status; 


     internal List<string> Updates { get; set; } 

     private void AddUpdate(string updates) 
     { 
      // Do stuff 
     } 
    } 

So habe ich verschiedene Methoden, die Ich mag würde in diese so wie weitergeben müssen:

public class AvailableTasks 
{ 
    public async void DoStuffThatIsCancelable(CancellationToken token) 
    { 
     DoTheLongStuffOnRepeat(token); 
    } 
    public async void DoAnotherThingThatIsCancelable(CancellationToken token) 
    { 
     DoTheLongStuffOnRepeat(token); 
    } 

    private async void DoTheLongStuffOnRepeat(CancellationToken token) 
    { 
     // Do stuff 
     for (int i = 0; i < 20; i++) 
     { 
      while (!token.IsCancellationRequested) 
      { 
       try 
       { 
        await Task.Delay(500, token); 
       } 
       catch (TaskCanceledException ex) 
       { 
        Console.WriteLine("Task was cancelled"); 
        continue; 
       } 
       Console.WriteLine($"Task Loop at {(i + 1) * 500}"); 
      } 
     } 
    } 
} 

Hier ist, wie ich es nennen dachte.

private static readonly List<ManagedTask> _managedTasks = new List<ManagedTask>(); 

    public static void SetupManagedTasks() 
    { 
     var at = new AvailableTasks(); 
     var mt1 = new ManagedTask 
     { 
      Id = 1, 
      DescriptiveName = "The cancelable task", 
      TheVoidToRun = at.DoStuffThatIsCancelable, 
     }; 
     _managedTasks.Add(mt1); 

     var mt2 = new ManagedTask 
     { 
      Id = 2, 
      DescriptiveName = "Another cancelable task", 
      TheVoidToRun = at.DoAnotherThingThatIsCancelable, 
     }; 
     _managedTasks.Add(mt2); 

     mt1.StartIt(); 
     mt2.StartIt(); 

     Console.WriteLine($"{mt1.DescriptiveName} status: {mt1.TheTaskStatus()}"); 
     Console.WriteLine($"{mt2.DescriptiveName} status: {mt2.TheTaskStatus()}"); 
    } 

    public static void CancelTask(int id) 
    { 
     var mt = _managedTasks.FirstOrDefault(t => t.Id == id); 

     if (mt != null) 
     { 
      mt.EndIt(); 
      Console.WriteLine($"{mt.DescriptiveName} status: {mt.TheTaskStatus()}"); 
     } 
    } 

    public static void GetTaskStatus(int id) 
    { 
     var mt = _managedTasks.FirstOrDefault(t => t.Id == id); 

     if (mt != null) 
     { 
      Console.WriteLine($"{mt.DescriptiveName} status: {mt.TheTaskStatus()}"); 
     } 
    } 

Aber selbst mit all dem oben genannten, leide ich unter dem Status immer nur RanToCompletion.

Wie kann ich das Obige strukturieren, um zu erreichen, was ich will?

Danke, David

+0

Es könnte ausreichen, die 'TaskCanceledException' erneut auszulösen, anstatt sie zu ignorieren. – Dirk

Antwort

0

leiden ich aus dem Stand überhaupt nur RanToCompletion zeigt.

Dies liegt daran, dass Ihre Methoden async void verwenden. Sie sollten async Task sein. Wie ich in meinem async best practices article beschreibe, solltest du async void vermeiden.

Andere Anmerkungen ...

Start Methode/Aufgaben

Restart eine Methode/Aufgaben

können Sie starten (oder Neustart) eine Aufgabe auf dem Thread-Pool unter Verwendung von Task.Run. Wenn Sie jedoch natürlich asynchrone Aufgaben haben, können Sie sie als Func<Task> darstellen und einfach die Func<Task> aufrufen, um sie zu starten.

Beenden einer Methode/Aufgaben

Der einzige geeignete Weg, dies mit einem CancellationToken zu tun ist, die es, wie Sie richtig verwenden aussieht.

Feedback Entfliehen Sie log/Aktuelles/progress/Fehler ist, dass ich auf Updates Liste aufnehmen

Ich empfehle IProgress<T> für jede Art von Fortschritt Updates verwenden.