2012-05-19 7 views
7

Ich versuche derzeit, eine Menge existierender synchroner Codes nach WinRT zu portieren.Welche Risiken bestehen beim Umbruch von Async/IAsyncOperationen mit Task.Wait() - Code?

Als Teil davon habe ich Probleme mit dem vorhandenen Code, der erwartet, dass einige Operationen synchron sind - z. für Datei-I/O

diesen bestehenden Code anzupassen mit dem IAsyncOperation Stil API innerhalb WinRT zu arbeiten, habe ich eine Technik zum Einwickeln des IAsyncOperation mit einem Verlängerungsverfahren wie verwendet:

namespace Cirrious.MvvmCross.Plugins.File.WinRT 
{ 
    public static class WinRTExtensionMethods 
    { 
     public static TResult Await<TResult>(this IAsyncOperation<TResult> operation) 
     { 
      var task = operation.AsTask(); 
      task.Wait(); 
      if (task.Exception != null) 
      { 
       // TODO - is this correct? 
       throw task.Exception.InnerException; 
      } 

      return task.Result; 
     } 
    } 
} 

von MvvmCross WinRT ExtensionMethods - mit einem ähnlichen Verfahren für IAsyncAction

diese Wrapper scheint zu funktionieren - und sie erlauben mir die Async Methoden in synchronem Code zu verwenden, wie:

public IEnumerable<string> GetFilesIn(string folderPath) 
    { 
     var folder = StorageFolder.GetFolderFromPathAsync(ToFullPath(folderPath)).Await(); 
     var files = folder.GetFilesAsync().Await(); 
     return files.Select(x => x.Name); 
    } 

Ich verstehe, dass dies nicht wirklich im Sinne von WinRT ist; aber ich erwarte, dass diese Methoden normalerweise nur auf Hintergrund-Threads aufgerufen werden; und ich schreibe dies mit dem Ziel, meinen Code plattformübergreifend kompatibel zu machen - auch auf Plattformen, die noch nicht auf async warten und/oder auf Entwickler, die noch nicht bereit sind, den Sprung zu machen.

Also ... die Frage ist: Mit welchen Risiken gehe ich mit dieser Art von Code?

Und als eine zweite Frage, gibt es eine bessere Möglichkeit, Code Wiederverwendung für Bereiche wie File I/O zu erreichen?

+0

http://feedproxy.google.com/~r/AyendeRahien/~3/71OP6uo3bTQ/when-using-the-task-parallel-library-wait-is-a-bad-warning-sign –

Antwort

2

ich endlich das geht zu beantworten ....

Und die Antwort ist, dass Sie nicht wirklich tun können.

Auch wenn Sie versuchen, einige der in den anderen Antworten vorgeschlagenen saubereren Methoden zu verwenden, treffen Sie immer noch Ausnahmen, wenn Sie versuchen, den Code auf einem Thread auszuführen, der versprochen hat, nicht zu blockieren - z. wenn Sie versuchen, auf dem UI-Thread oder einem Thread-Thread zu laufen.

Also ... die Antwort ist, dass Sie einfach diesen alten Code rearchitect, so dass es in irgendeiner Weise asynchron ist!

3

Erstens glaube ich, Ihre Methode wie folgt umgeschrieben werden:

public static TResult Await<TResult>(this IAsyncOperation<TResult> operation) 
{ 
    return operation.AsTask().Result; 
} 

Aufruf Result wird synchron warten, wenn die Aufgabe noch nicht beendet. Und es wird ein AgreggateException werfen, wenn es fehlschlägt. Ich denke, das InnerException zu werfen, wie Sie tun, ist eine schlechte Idee, weil es die Stapelspur der Ausnahme überschreibt.

In Bezug auf Ihre eigentliche Frage, denke ich, die größte Gefahr bei der Verwendung Wait() zusammen mit asynchronem Code sind Deadlocks. Wenn Sie eine Operation starten, die intern await für den Benutzeroberflächenthread verwendet und Sie dann auf Wait() für denselben Thread warten, erhalten Sie einen Deadlock.

Dies ist nicht so wichtig, wenn Sie nicht auf dem UI-Thread sind, aber Sie sollten es immer noch vermeiden, wenn es möglich ist, weil es gegen die gesamte async Idee geht.

+0

Danke für die Antworten. In der Ausnahmefrage versuche ich, dass der umgebende Code Ausnahmen wie FileNotFoundException erwartet - und ich kann nicht wirklich erwarten, dass sie mit AggregatedException umgehen. Alles in allem ist dies jedoch eine hoffnungslose Lösung von mir - längerfristig werde ich entweder die API umschreiben, um Action Callbacks zu verwenden, oder vielleicht werde ich auch auf den anderen Plattformen warten (Unterstützung ist Kommen zu MonoTouch und MonoDroid, wenn vs11/C# 4.5 aus der Beta kommt!) – Stuart

+0

FWIW, scheint seine mehr im Einklang mit dem erwarten Schlüsselwort, da es die innere Ausnahme statt der Aggregat geworfen wird. –

2

Es gibt viele gute Gründe, dies nicht zu tun. Siehe zum Beispiel http://blogs.msdn.com/b/pfxteam/archive/2012/04/13/10293638.aspx

Aber wenn Sie es tun wollen, verwenden Sie das GetResults() -Methode als

public static TResult Await<TResult>(this IAsyncOperation<TResult> operation) 
{ 
    try 
    { 
     return operation.GetResults(); 
    } 
    finally 
    { 
     operation.Close(); 
    } 
} 

folgte in einer Aufgabe, die IAsyncOperation Wrapping, wie svick erwähnt, funktioniert auch, ist aber weniger effizient.

+1

Ich konnte das nicht zum Laufen bringen. Ich habe den folgenden Code ausprobiert: var ordner = ApplicationData.Current.LocalFolder; var items = Ordner.CreateItemQuery(). GetItemsAsync(). Await(); und haben: Eine Ausnahme vom Typ 'System.InvalidOperationException' aufgetreten in GetResults. Weitere Informationen: Eine Methode wurde zu einem unerwarteten Zeitpunkt aufgerufen. (Ausnahme von HRESULT: 0x8000000E). AsTask(). Das Ergebnis hat funktioniert. –

+0

Ich hatte das gleiche Problem und deshalb habe ich diesen Beitrag gefunden. GetResults() hat nicht funktioniert, aber AsTask(). Ergebnis hat gut funktioniert – noggin182

Verwandte Themen