2012-04-15 7 views
4

Zum Beispiel stellt sagen wir, ich bin ein Verfahren mit den unten Signatur (C# 4 also keine async keywords) zu schreiben:Erstellen einer Aufgabe, die eine Reihe von Weiter Aufgaben

public Task Refresh(); 

Es ist eine Methode aufrufen wird (die auch eine Task) zurückgibt, um die Kommunikationsarbeit auszuführen, und dann eine Taskfortsetzung auszuführen, um einige interne Zustände basierend auf den abgerufenen Daten zu aktualisieren. z:

public Task Refresh() 
{ 
    Task<MyData> commsTask = datasource.LoadData(); 
    Task handleDataTask = commsTask.ContinueWith(HandleNewData); 

    return ?; 
} 

Wenn ich die handleDataTask Return.Spuren es ist Vollendungszustand korrekt das Ergebnis der Operation ‚Aktualisieren‘, aber es berichten nicht richtig es Zustand gestartet wird.

Ich kann beide in einem neuen Task.Factory.StartNew umhüllen und sie als untergeordnete Aufgaben erstellen, aber es scheint verschwenderisch, einen neuen Thread zu spoolen, nur um einige Task-Fortsetzungen zu verknüpfen.

Sicherlich gibt es eine ordentlich effiziente Möglichkeit, dies mit dem TPL zu tun?

+0

Warum interessiert dich der Staat? – svick

+0

Damit die Implementierung mit der impliziten Dokumentation der Methodensignatur übereinstimmt? Ich weiß es nicht, frage die Verbraucher nach meiner Methode. Es gibt wahrscheinlich 100s von möglichen Verwendungen für die 'Task.Status'-Eigenschaft, alles was ich weiß ist, dass meine Methode eine 'Task' zurückgeben sollte, die korrekt ihrer Dokumentation folgt. – Tyson

Antwort

3

Normalerweise wird Task.Status nur verwendet, um über den Endzustand herauszufinden. Sie können sich nicht darauf verlassen, dass die Aufgabe sowieso Started ist, da sich dieser Zustand jederzeit ändern kann.

Aus diesem Grund spielt es keine Rolle, ob die Aufgabe, die Sie zurückgeben, einen "seltsamen" Status hat, bis sie abgeschlossen ist. Nur die drei abgeschlossenen Staaten (Completed, Canceled, Faulted) sind von Bedeutung.

+0

Ich stimme den 3 Endstaaten zu, die wichtig sind. Aber es gibt keine Garantie, dass die letzte Aufgabe ausgeführt wird. Wenn Sie also Ihre letzte Aufgabe in der Kette zurückgeben, riskieren Sie, dass die von Ihnen zurückgegebene Task-Instanz, die die gesamte Operation darstellt, dauerhaft in "WaitingForActivation" steckt. Ich habe es nicht in das Beispiel aufgenommen, aber es ist möglich, dass Task-Continuations nicht ausgeführt werden, wenn vorhergehende Tasks abgebrochen werden. – Tyson

+1

@Tyson, wenn die Antezedens-Aufgabe abgebrochen wird, wird die Fortsetzungsaufgabe normalerweise ausgeführt. Wenn Sie 'TaskContinuationOptions' verwenden, um das zu ändern, wird die Fortsetzung ebenfalls abgebrochen.Aus diesem Grund wird es nicht im 'WaitingForActivation'-Status hängen bleiben (es sei denn, der Antezedens enthält eine Endlosschleife oder einen Deadlock). – svick

+0

@svick Hmm ... Ich kann die Referenz jetzt nicht finden, aber ich erinnere mich an ein Beispiel, in dem eine Task-Fortsetzung nicht ausgeführt wurde. Obwohl ich jetzt nachdenke, obwohl es nicht lief, ging es immer noch direkt in den Zustand 'Ausgelöscht', wie du sagst. Ich weiß nicht, es fühlt sich immer noch chaotisch an, die letzte Aufgabe, die gesamte Sequenz darzustellen, zurückzugeben. – Tyson

0

habe ich einige weitere Forschung und fand eine ähnliche SO Fragen, und einige Blog-Beiträge:

Task chaining without TaskCompletionSource?

http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx

http://msmvps.com/blogs/jon_skeet/archive/2011/05/20/eduasync-part-7-generated-code-from-a-simple-async-method.aspx

So gibt es eine halbe Antwort - man kann Erstellen Sie eine Task-Instanz, die alle untergeordneten Tasks darstellt, ohne einen neuen Thread aufzuspulen und sie als untergeordnete Tasks anzuhängen: Verwenden Sie einfach eine TaskCompletionSource. Einfaches Beispiel unten auf meine Frage oben ohne Ausfall oder Rückgängigmachung Handhabung angewandt:

public Task Refresh() 
{ 
    var refreshTaskSource = new TaskCompletionSource<object>(); 

    Task<MyData> commsTask = datasource.LoadData(); 
    Task handleDataTask = commsTask.ContinueWith(HandleNewData); 
    handleDataTask.ContinueWith(t => refreshTaskSource.SetResult(null)); 

    return refreshTaskSource.Task; 
} 

jedoch die Aufgabe nach dieser Methode nun wieder Übergänge gerade TaskStatus.WaitingForActivation-TaskStatus.RanToCompletion (oder Faulted/Cancelled wenn ich behandeln diese Szenarien habe) .

Verwandte Themen