2017-12-07 5 views
0

Ästhetische Frage wirklich.Verkettung von C# async/warten auf Tasks, sie neu erstellen, wie sie fertig sind

diesen Code (Polling unvermeidlich) Gegeben:

protected override async Task ExecuteAsync(CancellationToken ct) 
{  
    // move the loop here somehow? 
    await Task.WhenAll(
     Task.Run(async() => await this.PollA(ct), ct), 
     Task.Run(async() => await this.PollB(ct), ct), 
     Task.Run(async() => await this.PollC(ct), ct)) 
     .ConfigureAwait(false); 
} 

die Methoden zur Zeit wie folgt aussehen Polling, hat jeder eine andere Verzögerung.

private async Task Poll(CancellationToken ct) 
{ 
    while (!ct.IsCancellationRequested) 
    { 
     await Task.Delay(Math.Max(1000, CONFIGA), ct); 
     this._logger.StartAction("poll A status"); 
     this._logger.StopAction("poll A status"); 
    } 
} 

Gibt es eine Möglichkeit, eine Fortsetzung zu strukturieren, dass die Schleife in jedem der Poll Methoden

private async Task Poll(CancellationToken ct) 
{ 
    await Task.Delay(Math.Max(1000, CONFIGA), ct); 
    this._logger.StartAction("poll A status"); 
    this._logger.StopAction("poll A status"); 
} 

Dies könnte nicht einmal seine das richtige Muster entfernt, aber es scheint besser als drei Endlosschleifen haben.

+1

Warum nicht einfach 'erwarten Task.WhenAll (this.PollA (ct), this.PollB (ct), this.PollC (ct)) '? Aber sicherlich können Sie einfach 'while (! Ct.IsCancellationRequested) auf Task.WhenAny warten (this.PollA (ct), this.PollB (ct), this.PollC (ct))' wenn das das gewünschte Verhalten wäre. –

Antwort

1

Ich habe eine ästhetische Lösung, die wahrscheinlich nicht ratsam ist, da es wahrscheinlich Stapelüberlauf schließlich verursachen wird. Es zeigt vielleicht, warum die Schleife eine bessere Option ist.

Ich muss zugeben, nicht wirklich verstehen, Ihr Beispiel in einem realen Kontext. In meinem Kopf wird fast der gesamte Code, der für eine lange Zeit ausgeführt wird, es in einer endlichen Schleife tun, und daher scheint es für mich eine gute Idee zu sein, nach jeder Schleifeniteration nach einer Löschung zu suchen.

Es sei denn, Sie möchten, dass Ihr Code nur unendlich läuft, bis die Aufgabe abgebrochen wird. In diesem Fall wird meine ästhetische Lösung wahrscheinlich einen Stapelüberlauf verursachen, aber es hat Spaß gemacht, diesen Code zu erstellen.

habe ich eine Erweiterung Methode:

public static class Extensions 
{ 
    public static async Task ContinueWithInfinitly(this Task task, Func<Task> continuationAction, CancellationToken cancellationToken) 
    { 
     await task; 
     if (!cancellationToken.IsCancellationRequested) 
     { 
      var newTask = continuationAction.Invoke(); 
      await newTask.ContinueWithInfinitly(continuationAction, cancellationToken); 
     } 
    } 
} 

, die auf Ihrem Code-Basis wird dann wie folgt aufgerufen werden:

await Task.WhenAll(
       Task.Run(async() => await this.PollA(ct).ContinueWithInfinitly(() => PollA(ct), ct)), 
       Task.Run(async() => await this.PollB(ct).ContinueWithInfinitly(() => PollB(ct), ct)), 
       Task.Run(async() => await this.PollC(ct).ContinueWithInfinitly(() => PollC(ct), ct))) 
       .ConfigureAwait(false); 

Obwohl ich von Verpackungs jede Methode wieder in einer Aufgabe den Punkt nicht sehen .Lauf. So kann ich auch sein gerade

await Task.WhenAll(
       this.PollA(ct).ContinueWithInfinitly(() => PollA(ct), ct), 
       this.PollB(ct).ContinueWithInfinitly(() => PollB(ct), ct), 
       this.PollC(ct).ContinueWithInfinitly(() => PollC(ct), ct)) 
       .ConfigureAwait(false); 
+0

mmh, das wird funktionieren - obwohl ich vermute, dass das Muster gebrochen ist, und es ist besser, nur die Schleifen zu verwenden ... danke. Ich denke, du bist auch richtig über die inhärenten Stack-Probleme ... – Jim

+1

@Jim Ja, es ist kaputt, ich denke auf eine Weise zeigt dies, warum Sie Schleifen verwenden sollten, weil die Alternative schlechter ist –

+0

Ich dachte, dass eine Gewohnheit 'Awaitable' könnte den Trick machen, aber ich denke, es wird auch am Ende chaotisch aussehen. – Jim

0

Sie Task.WhenAny wie diese verwenden:

private async Task<Tuple<string, int>> Poll(string type, int delay, CancellationToken ct) { 
    await Task.Delay(Math.Max(1000, delay), ct); 
    Console.WriteLine($"poll {type} status"); 
    // return input arguments back 
    return Tuple.Create(type, delay); 
} 

private async Task PollAll(CancellationToken ct) { 
    var tasks = new [] 
    { 
     Poll("A", 3000, ct), 
     Poll("B", 2000, ct), 
     Poll("C", 1000, ct) 
    }; 
    while (!ct.IsCancellationRequested) { 
     var completed = await Task.WhenAny(tasks); 
     var index = Array.IndexOf(tasks, completed); 
     // await to throw exceptions if any 
     await completed;         
     // replace with new task with the same arguments 
     tasks[index] = Poll(completed.Result.Item1, completed.Result.Item2, ct); 
    } 
} 
Verwandte Themen