2017-02-05 1 views
1

Ich bin ziemlich sicher, das wurde bereits beantwortet und ich lese viele verwandte Sachen, aber irgendwie bekomme ich es nicht in meinem Code zu arbeiten. Hier ist die genaue Codebasis.Wie und wann retour von der erwarteten (asynchronen) Methode

ich dieses async Methode in meiner Bibliothek haben, die eine Zeichenfolge auf dabei einige DB-Einträge zurückgibt:

public class MyLibrary 
{ 
public async Task<string> DoSomethingAsync() 
{ 
    return await DoAsync(); 
} 

// some private method, with multiple parameters 
private Task<string> DoAsync() 
{ 
    return Task.Run(() => Do()); 
} 
} 

nun auf UI, führte unter einen gefrorenen Zustand oder Deadlock:

var myTask = MyLibraryobject.DoSomethingAsync(); 
console.Write(myTask.Result); 

Seit mein Aufruf ist erwartbar, ich denke, UI-Thread wartet auf meinen Anruf, um sein Geschäft zu beenden und das Ergebnis zu bevölkern, nicht wahr? Oder da der Anruf in einem anderen Thread ausgeführt wird, ist die Aufgabe möglicherweise noch nicht abgeschlossen, wenn mein Cursor die Zeile 2 erreicht. Also, was nun? der Cursor wartet, bis die Aufgabe abgeschlossen ist oder die Zeile 2 ausgeführt wird, wenn die Aufgabe abgeschlossen ist? klingt synchron zu mir ..

Auch wenn überhaupt, ich möchte 'explizit' warten, bis die Aufgabe beendet ist, wie kann ich das erzwingen? einige Beiträge, schlug wie unten zu tun, die gab mir das Ergebnis, sondern schuf etwas mehr Verwirrung:

var myTask = Task.Run(async() => await MyLibraryobject.DoSomethingAsync()); 
myTask.Wait(); 
console.Write(myTask.Result); 

Was oben ist passiert? Warum sollte ich eine andere Aufgabe erstellen und sie warten lassen? kann ich nicht auf den Thread warten, der von der Async-Methode verwendet wird? Auch hier fehlen mir einige grundlegende Dinge.

Schließlich ist dies ein Async-Aufruf, aber der UI-Thread wartet darauf, dass er abgeschlossen wird, und gibt mir den Eindruck, dass er synchron ist. Denke ich es richtig? Was ist der Hauptzweck von asynchronen Methoden, die etwas zurückgeben und die UI darauf wartet, dass sie abgeschlossen wird?

Auch was ist der Unterschied zwischen einem Fire-and-Forget-Aufruf, der nicht asynchron und asynchron ist? Gibt es einen Vorteil dafür, dass die Task für solche Aufrufe nicht storniert wird?

Ich bin ziemlich sicher, ein gebrochener Link, der all diese Teile in meinem Gehirn verbindet. Kann mir das bitte jemand erklären?

+2

Wenn Sie eine asynchrone Methode aufrufen, können Sie nicht garantieren, dass der Inhalt in einem anderen Thread als dem aufrufenden Thread ausgeführt wird. Deshalb sollten Sie es irgendwann in 'Task.Run' (oder' Task.Factory.StartNew') einfügen. Wenn Sie 'myTask.Result 'aufrufen, ist' myTask.Wait() 'außerdem implizit. Um das Blockieren der Thread-Benutzeroberfläche zu vermeiden, sollten Sie Ihre Ereignishandlermethode als async markieren. – Kalten

Antwort

1

nun auf UI, führte unter einem gefrorenen Zustand oder Deadlock:

var myTask = MyLibraryobject.DoSomethingAsync(); 

Dieses UI blockiert, weil es nicht erwartet wird. Sie müssen lediglich auf eine asynchrone Methode warten:

und das obige sollte auch in der Benutzeroberfläche in einem asynchronen Kontext platziert werden.

Bearbeiten - antworten Sie auf Kommentar Do "meinst du eine andere Wrapper async-Methode, die Task<string> ... zurückgibt?"? Nein, ich nicht. Wenn ich "innerhalb eines asynchronen Kontexts" schrieb, wollte ich das asynchrone Schlüsselwort zu einem abonnierten Ereignis hinzufügen, z. B. einem Klick auf die Schaltfläche, wenn Sie sich im Code oder in der Delegiertenbefehlsimplementierung befinden, wenn Sie eine erweiterte MVVM-Implementierung von die GUI.

Darüber hinaus soll Ihre Klassenbibliothek etwas wirklich Asynchrones tun, nicht nur eine Aufgabe starten und sie in eine formal asynchrone Methode einbetten, so wie es Ihre DoAsync ist.

Edit - als Antwort auf den Kommentar "wie sollte man es vermeiden"?Wenn Sie den gesamten Weg nicht asyncieren können, halten Sie einfach die Bibliothek und die API, um die Benutzeroberfläche zu synchronisieren und zu entsperren, indem Sie einen separaten Thread starten, um die sync-API aufzurufen.

+0

Sie meinen eine andere Wrapper-Async-Methode, die Task zurückgibt, die einen Aufruf wie folgt hat: 'return await MyLibraryobject.DoSomethingAsync()'? Außerdem verstehe ich nicht, was ich sonst in meiner Bibliotheksmethode tun sollte? – Skip

+0

Ok. Ich rufe diese Bibliotheksmethode in einer API-Methode auf und das ist der Grund, warum ich das Schlüsselwort "erwarten" nicht direkt hier verwendet habe, da es mich zwingen würde, der API-Methode ein asynchrones Schlüsselwort hinzuzufügen. Also habe ich einen Wrapper erstellt, der einfach die Aufgabe zurückgibt, die erwartet wird, wie 'return await MyLibraryobject.DoSomethingAsync()'. Aber das hat nicht funktioniert. Nach Ihrem Kommentar habe ich 'async' zur API-Methode hinzugefügt und verwendet und das Ergebnis erhalten, nur Sie erwähnt. Meine Verwirrung ist, warum es früher nicht geklappt hat, als ich im Wrapper dasselbe "Warten" gemacht habe. Wird beim Erstellen eines Wrappers auf eine andere Aufgabe verwiesen? – Skip

+0

Außerdem habe ich verstanden, dass ich kein asynchrones Pendant veröffentlichen sollte, das einfach die synchrone Methode in Task.Run umschließt. Genau das habe ich mit meiner Bibliotheksmethode gemacht; es war vorher sync und ich machte es async, indem ich in Task.Run einwickelte. Wie sollte ich solche Praktiken vermeiden und trotzdem eine asynchrone Version haben? – Skip

2

Sie sollten wahrscheinlich mit meinem async intro beginnen und meinen Artikel auf async best practices folgen. Sie beantworten fast alle Ihre Fragen.

Für die Details ...

, wie und wann die Rückkehr von awaitable (async) Methode

holen Sie sollten await verwenden das Ergebnis von einer Asynchron-Aufgabe zu bekommen.

Ich habe dieses Asynchron-Methode in meiner Bibliothek, die auf dabei einige DB Einträge

Dann sollte es nicht Task.Run werden mit einem String zurückgibt. Es sollte natürlich-asynchrone APIs verwenden, z. B. FirstAsync von Entity Framework.

Da mein Aufruf ist zu erwarten, glaube ich, UI-Thread wartet auf meinen Anruf, um sein Geschäft zu beenden und das Ergebnis zu befüllen, nicht wahr?

Nein. Die Benutzeroberfläche blockiert, weil Ihr Code Result aufruft. Result ist ein blockierender Anruf.

klingt synchron zu mir ..

Das ist, weil Sie es synchron zu machen von Result verwenden. Wenn Sie await verwenden, führt der Code seriell, aber asynchron aus.

Auch wenn ich überhaupt 'explizit' warten möchte, bis die Aufgabe beendet ist, wie erzwinge ich das?

Ihr Code macht das bereits. Es blockiert explizit, bis die Aufgabe abgeschlossen ist. Wenn Sie es ändern, um await richtig zu verwenden, wird es explizit warten (aber nicht blockieren), bis die Aufgabe abgeschlossen ist.

einige Beiträge, schlug wie

Nr unten

dabei Sie Task.Run nicht unnötig verwenden.

kann ich nicht auf den Thread warten, der von der Async-Methode verwendet wird?

Reine Async-Methoden haben keine Threads, die sie verwenden.

Was ist dann der Hauptzweck der asynchronen Methoden, die etwas zurückgeben und die UI darauf wartet, dass sie abgeschlossen wird?

Async macht Sinn, wenn es mit await verbraucht wird.

+0

Danke; Ich lese deine Sachen. Da die Dinge nicht geklappt haben, wurde ich zweifelnd an meinem eigenen Verständnis. Ich fügte meine Erklärung hinzu, warum ich in dem anderen Kommentar nicht "warten" hinzugefügt habe. Macht es Ihnen etwas aus, das Zeug dahinter zu erklären? – Skip

+0

Ich verstehe deinen Kommentar nicht wirklich. Wenn Sie "async" und "erwarten" den ganzen Weg verwenden, dann wird es mit oder ohne den Wrapper arbeiten. –

+0

Sorry, konnte nicht klar auf mein Problem sein! Test1: 'MyOriginalMethod() {string result = Lib.AsyncMethod(). Ergebnis; // funktioniert nicht} ' Test2: ' MyOriginalMethod() {string result = wrapper.wrapperAsyncMethod(). Ergebnis; // funktioniert nicht} wrapperAsyncMethod() {return erwartet Lib.AsyncMethod();} ' Test3: ' Async MyOriginalMethod() {Zeichenfolge result = await Lib.AsyncMethod(); // funktioniert} ' Und MyOriginalMethod() ist eine API-Methode, und die Test3, was ich mit 'Inline erwarten' – Skip

Verwandte Themen