Ich lerne etwas über Async / Warten und bin auf eine Situation gestoßen, in der ich eine Async-Methode synchron aufrufen muss. Wie kann ich das machen?
Asynchrone Methode:
public async Task<Customers> GetCustomers()
{
return await Service.GetCustomersAsync();
}
Normaler Gebrauch:
public async void GetCustomers()
{
customerList = await GetCustomers();
}
Ich habe versucht, Folgendes zu verwenden:
Task<Customer> task = GetCustomers();
task.Wait()
Task<Customer> task = GetCustomers();
task.RunSynchronously();
Task<Customer> task = GetCustomers();
while(task.Status != TaskStatus.RanToCompletion)
Ich habe auch einen Vorschlag von hier aus versucht , aber er funktioniert nicht, wenn sich der Dispatcher in einem suspendierten Zustand befindet.
public static void WaitWithPumping(this Task task)
{
if (task == null) throw new ArgumentNullException(“task”);
var nestedFrame = new DispatcherFrame();
task.ContinueWith(_ => nestedFrame.Continue = false);
Dispatcher.PushFrame(nestedFrame);
task.Wait();
}
Hier ist die Ausnahme und die Stapelverfolgung beim Aufrufen RunSynchronously
:
System.InvalidOperationException
Nachricht : RunSynchronously darf nicht für eine Aufgabe aufgerufen werden, die nicht an einen Delegaten gebunden ist.
InnerException : null
Quelle : mscorlib
StackTrace :
at System.Threading.Tasks.Task.InternalRunSynchronously(TaskScheduler scheduler)
at System.Threading.Tasks.Task.RunSynchronously()
at MyApplication.CustomControls.Controls.MyCustomControl.CreateAvailablePanelList() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 638
at MyApplication.CustomControls.Controls.MyCustomControl.get_AvailablePanels() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 233
at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>b__36(DesktopPanel panel) in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 597
at System.Collections.Generic.List`1.ForEach(Action`1 action)
at MyApplication.CustomControls.Controls.MyCustomControl.<CreateOpenPanelList>d__3b.MoveNext() in C:\Documents and Settings\...\MyApplication.CustomControls\Controls\MyCustomControl.xaml.cs:line 625
at System.Runtime.CompilerServices.TaskAwaiter.<>c__DisplayClass7.<TrySetContinuationForAwait>b__1(Object state)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOperation.InvokeImpl()
at System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object state)
at System.Threading.ExecutionContext.runTryCode(Object userData)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOperation.Invoke()
at System.Windows.Threading.Dispatcher.ProcessQueue()
at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunDispatcher(Object ignore)
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at MyApplication.App.Main() in C:\Documents and Settings\...\MyApplication\obj\Debug\App.g.cs:line 50
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
c#
asynchronous
c#-5.0
async-await
Rachel
quelle
quelle
Task
synchrone Verwendung . 3) Ich integriere GeneXus in den MongoDB C # -Treiber , der einige Methoden nur asynchronSemaphoreSlim
.Antworten:
Hier ist eine Problemumgehung, die in allen Fällen funktioniert (einschließlich suspendierter Disponenten). Es ist nicht mein Code und ich arbeite immer noch daran, ihn vollständig zu verstehen, aber es funktioniert.
Es kann aufgerufen werden mit:
customerList = AsyncHelpers.RunSync<List<Customer>>(() => GetCustomers());
Code ist von hier
quelle
DynamicNodeProviderBase
Basisklasse erweitert, kann man es nicht alsasync
Methode deklarieren . Entweder musste ich durch eine neue Bibliothek ersetzen oder einfach eine synchrone Operation aufrufen.AspNetSynchronizationContext
, sodass dieser bestimmte Hack nicht funktioniert, wenn Sie diese APIs aufrufen.Bitte beachten Sie, dass diese Antwort drei Jahre alt ist. Ich habe es hauptsächlich aufgrund von Erfahrungen mit .Net 4.0 geschrieben und sehr wenig mit 4.5, insbesondere mit
async-await
. Im Allgemeinen ist es eine schöne einfache Lösung, aber manchmal bricht es Dinge. Bitte lesen Sie die Diskussion in den Kommentaren..Net 4.5
Verwenden Sie einfach dies:
Siehe: TaskAwaiter , Task.Result , Task.RunSynchronously
.Net 4.0
Benutze das:
...oder dieses:
quelle
.Result
kann in bestimmten Szenarien einen Deadlock erzeugenResult
kann leicht zu einem Deadlock imasync
Code führen , wie ich in meinem Blog beschreibe.Überrascht erwähnte niemand dies:
Nicht so hübsch wie einige der anderen Methoden hier, aber es hat die folgenden Vorteile:
Wait
)AggregateException
(likeResult
) geworfen.Task
undTask<T>
( probieren Sie es selbst aus! )Da
GetAwaiter
dies vom Typ Ente ist, sollte dies auch für jedes Objekt funktionieren, das von einer asynchronen Methode (wieConfiguredAwaitable
oderYieldAwaitable
) zurückgegeben wird, nicht nur für Aufgaben.Bearbeiten: Bitte beachten Sie, dass dieser Ansatz (oder seine Verwendung
.Result
) zum Deadlock führen kann, es sei denn, Sie stellen sicher, dass Sie.ConfigureAwait(false)
jedes Mal , wenn Sie warten, alle asynchronen Methoden hinzufügen , von denen aus möglicherweise erreicht werden kannBlahAsync()
(nicht nur diejenigen, die direkt aufgerufen werden). Erklärung .Wenn Sie zu faul sind, um
.ConfigureAwait(false)
überall etwas hinzuzufügen , und Sie sich nicht für die Leistung interessieren, können Sie dies alternativ tunquelle
GetAwaiter()
: "Diese Methode ist für Compiler-Benutzer gedacht und nicht direkt im Code."Es ist viel einfacher, die Aufgabe im Thread-Pool auszuführen, als den Scheduler dazu zu bringen, sie synchron auszuführen. Auf diese Weise können Sie sicher sein, dass es nicht zum Stillstand kommt. Die Leistung wird durch den Kontextwechsel beeinträchtigt.
quelle
Task.Run(DoSomethingAsync)
stattdessen einfach schreiben ? Dadurch wird eine Ebene von Delegierten entfernt.Task<MyResult> task = Task.Run(async () => await DoSomethingAsync());
ist jedoch expliziter , in die entgegengesetzte Richtung zu gehen, da dies expliziter ist und die Besorgnis von @sgnsajgon anspricht, dass möglicherweise eine Aufgabe <Aufgabe <Mein Ergebnis >> zurückgegeben wird. Die richtige Überladung von Task.Run wird in beiden Fällen ausgewählt, aber der asynchrone Delegat macht Ihre Absicht offensichtlich.Die beste Antwort ist, dass Sie dies nicht tun. Die Details hängen von der "Situation" ab.
Ist es ein Property Getter / Setter? In den meisten Fällen ist es besser, asynchrone Methoden als "asynchrone Eigenschaften" zu haben. (Weitere Informationen finden Sie in meinem Blogbeitrag zu asynchronen Eigenschaften. )
Ist dies eine MVVM-App und möchten Sie eine asynchrone Datenbindung durchführen? Verwenden Sie dann so etwas wie my
NotifyTask
, wie in meinem MSDN-Artikel zur asynchronen Datenbindung beschrieben .Ist es ein Konstruktor? Dann möchten Sie wahrscheinlich eine asynchrone Factory-Methode in Betracht ziehen. (Weitere Informationen finden Sie in meinem Blogbeitrag zu asynchronen Konstruktoren. )
Es gibt fast immer eine bessere Antwort als Sync-over-Async.
Wenn es für Ihre Situation nicht möglich ist (und Sie dies wissen, indem Sie hier eine Frage stellen, die die Situation beschreibt ), würde ich empfehlen, nur synchronen Code zu verwenden. Async den ganzen Weg ist am besten; Die vollständige Synchronisierung ist die zweitbeste. Sync-over-Async wird nicht empfohlen.
Es gibt jedoch eine Handvoll Situationen, in denen eine Synchronisierung über Asynchronisierung erforderlich ist. Insbesondere werden Sie so durch den anrufenden Code eingeschränkt , dass Sie haben vollkommen synchron sein (und haben absolut keine Möglichkeit , zu überdenken , oder Re-Struktur Code Asynchronität zu ermöglichen), und Sie haben Asynchron - Code aufzurufen. Dies ist eine sehr seltene Situation, die jedoch von Zeit zu Zeit auftritt.
In diesem Fall müßten Sie eine der Hacks in meinem Artikel beschrieben verwenden Bricht
async
Entwicklung , insbesondere:GetAwaiter().GetResult()
). Beachten Sie, dass dies zu Deadlocks führen kann (wie ich in meinem Blog beschreibe).Task.Run(..).GetAwaiter().GetResult()
. B. ). Beachten Sie, dass dies nur funktioniert, wenn der asynchrone Code in einem Thread-Pool-Thread ausgeführt werden kann (dh nicht von einer Benutzeroberfläche oder einem ASP.NET-Kontext abhängig ist).Verschachtelte Nachrichtenschleifen sind die gefährlichsten aller Hacks, da sie zu einem erneuten Eintritt führen . Der Wiedereintritt ist äußerst schwierig zu begründen, und (IMO) ist die Ursache für die meisten Anwendungsfehler unter Windows. Insbesondere wenn Sie sich im UI-Thread befinden und eine Arbeitswarteschlange blockieren (warten, bis die asynchrone Arbeit abgeschlossen ist), führt die CLR tatsächlich ein Nachrichtenpumpen für Sie durch - sie verarbeitet tatsächlich einige Win32-Nachrichten aus Ihrem Code . Oh, und Sie haben keine Ahnung, welche Botschaften - wenn Chris Brumme sagt: "Wäre es nicht großartig, genau zu wissen, was gepumpt wird? Leider ist das Pumpen eine schwarze Kunst, die jenseits des sterblichen Verständnisses liegt." Dann haben wir wirklich keine Hoffnung zu wissen.
Wenn Sie also einen UI-Thread so blockieren, fragen Sie nach Problemen. Ein weiteres Zitat aus demselben Artikel: "Von Zeit zu Zeit stellen Kunden innerhalb oder außerhalb des Unternehmens fest, dass wir während des verwalteten Blockierens auf einem STA [UI-Thread] Nachrichten pumpen. Dies ist ein berechtigtes Problem, da sie wissen, dass es sehr schwierig ist Code zu schreiben, der angesichts von Wiedereintritten robust ist. "
Ja, so ist es. Es ist sehr schwer, Code zu schreiben, der angesichts von Wiedereintritten robust ist. Verschachtelte Nachrichtenschleifen zwingen Sie dazu, Code zu schreiben, der angesichts von Wiedereintritten robust ist. Aus diesem Grunde ist die akzeptierte (und meist upvoted) Antwort auf diese Frage ist sehr gefährlich in der Praxis.
Wenn Sie keine anderen Optionen mehr haben - Sie können Ihren Code nicht neu gestalten, Sie können ihn nicht so umstrukturieren, dass er asynchron ist - Sie werden durch unveränderlichen aufrufenden Code gezwungen, synchron zu sein - Sie können den nachgeschalteten Code nicht so ändern, dass er synchronisiert wird - Sie können nicht blockieren - Sie können den asynchronen Code nicht in einem separaten Thread ausführen - dann und nur dann sollten Sie in Betracht ziehen, die Wiedereintrittsfähigkeit zu übernehmen.
Wenn Sie sich in dieser Ecke befinden, würde ich empfehlen, etwas
Dispatcher.PushFrame
für WPF-Apps zu verwenden ,Application.DoEvents
für WinForm-Apps eine Schleife zu verwenden und für den allgemeinen Fall meine eigeneAsyncContext.Run
.quelle
Main()
Methode wird nicht kompiliert. an einem gewissen Punkt haben Sie bekommen die Lücke zwischen den sync und async Welten zu überbrücken. Dies ist keine " sehr seltene Situation" , sondern in buchstäblich jedem Programm erforderlich, das eine asynchrone Methode aufruft. Es gibt keine Option, nicht "Sync-over-Async" durchzuführen , sondern nur eine Option, um diese Belastung auf die aufrufende Methode zu verlagern, anstatt sie in diejenige zu übernehmen, die Sie gerade schreiben.async
jetzt alle Methoden in meiner Anwendung anwenden. Und das ist viel. Kann das nicht einfach die Standardeinstellung sein?Wenn ich Ihre Frage richtig lese, wird der Code, der den synchronen Aufruf einer asynchronen Methode wünscht, auf einem angehaltenen Dispatcher-Thread ausgeführt. Und Sie möchten diesen Thread tatsächlich synchron blockieren , bis die asynchrone Methode abgeschlossen ist.
Asynchrone Methoden in C # 5 werden unterstützt, indem die Methode effektiv unter der Haube in Stücke
Task
geschnitten und eine zurückgegeben wird , die den Gesamtabschluss des gesamten Shabang verfolgen kann. Wie die zerhackten Methoden ausgeführt werden, hängt jedoch vom Typ des an denawait
Operator übergebenen Ausdrucks ab .Meistens verwenden Sie
await
einen Ausdruck vom TypTask
. Die Implementierung desawait
Musters durch Task ist insofern "klug", als es sich von dem unterscheidetSynchronizationContext
, was im Grunde Folgendes bewirkt:await
eingeht, in einem Dispatcher- oder WinForms-Nachrichtenschleifenthread befindet, wird sichergestellt, dass die Blöcke der asynchronen Methode im Rahmen der Verarbeitung der Nachrichtenwarteschlange auftreten.await
einem Thread-Pool-Thread befindet, treten die verbleibenden Blöcke der asynchronen Methode an einer beliebigen Stelle im Thread-Pool auf.Aus diesem Grund treten wahrscheinlich Probleme auf - die Implementierung der asynchronen Methode versucht, den Rest auf dem Dispatcher auszuführen - obwohl er ausgesetzt ist.
.... sichern! ....
Ich muss die Frage stellen, warum Sie versuchen, eine asynchrone Methode synchron zu blockieren. Dies würde den Zweck zunichte machen, warum die Methode asynchron aufgerufen werden wollte. Wenn Sie mit der Verwendung
await
einer Dispatcher- oder UI-Methode beginnen, möchten Sie im Allgemeinen Ihren gesamten UI-Flow asynchronisieren. Zum Beispiel, wenn Ihr Callstack ungefähr so war:WebRequest.GetResponse()
YourCode.HelperMethod()
YourCode.AnotherMethod()
YourCode.EventHandlerMethod()
[UI Code].Plumbing()
-WPF
oderWinForms
CodeWPF
oderWinForms
NachrichtenschleifeSobald der Code für die Verwendung von Async transformiert wurde, erhalten Sie in der Regel Folgendes
WebRequest.GetResponseAsync()
YourCode.HelperMethodAsync()
YourCode.AnotherMethodAsync()
YourCode.EventHandlerMethodAsync()
[UI Code].Plumbing()
-WPF
oderWinForms
CodeWPF
oderWinForms
NachrichtenschleifeEigentlich antworten
Die obige AsyncHelpers-Klasse funktioniert tatsächlich, weil sie sich wie eine verschachtelte Nachrichtenschleife verhält, aber eine eigene parallele Mechanik für den Dispatcher installiert, anstatt zu versuchen, sie auf dem Dispatcher selbst auszuführen. Das ist eine Problemumgehung für Ihr Problem.
Eine andere Problemumgehung besteht darin, Ihre asynchrone Methode in einem Threadpool-Thread auszuführen und dann auf den Abschluss zu warten. Dies ist einfach - Sie können es mit dem folgenden Snippet tun:
Die endgültige API ist Task.Run (...), aber mit dem CTP benötigen Sie die Ex-Suffixe ( Erklärung hier ).
quelle
TaskEx.RunEx(GetCustomers).Result
hängt jedoch die Anwendung, wenn sie auf einem angehaltenen Dispatcher-Thread ausgeführt wird. Außerdem wird die GetCustomers () -Methode normalerweise asynchron ausgeführt. In einer Situation muss sie jedoch synchron ausgeführt werden. Daher habe ich nach einer Möglichkeit gesucht, dies zu tun, ohne eine Synchronisierungsversion der Methode zu erstellen.async
Methoden richtig anzuwenden. verschachtelte Schleifen sollten auf jeden Fall vermieden werden.Das funktioniert gut für mich
quelle
MyAsyncMethod().RunTaskSynchronously();
Der einfachste Weg, eine Aufgabe synchron und ohne Blockierung des UI-Threads auszuführen, besteht darin, RunSynchronously () wie folgt zu verwenden:
In meinem Fall habe ich ein Ereignis, das ausgelöst wird, wenn etwas auftritt. Ich weiß nicht, wie oft es vorkommen wird. Daher verwende ich in meinem Ereignis den oben genannten Code. Wenn er ausgelöst wird, wird eine Aufgabe erstellt. Aufgaben werden synchron ausgeführt und es funktioniert gut für mich. Ich war nur überrascht, dass ich so lange gebraucht habe, um herauszufinden, wie einfach es ist. Normalerweise sind Empfehlungen viel komplexer und fehleranfälliger. Das war es ist einfach und sauber.
quelle
Ich habe mich ein paar Mal damit auseinandergesetzt, hauptsächlich in Unit-Tests oder in einer Windows-Service-Entwicklung. Derzeit benutze ich immer diese Funktion:
Es ist einfach, leicht und ich hatte keine Probleme.
quelle
Ich habe diesen Code in der Microsoft.AspNet.Identity.Core-Komponente gefunden und er funktioniert.
quelle
Nur eine kleine Anmerkung - dieser Ansatz:
funktioniert für WinRT.
Lassen Sie mich erklären:
Darüber hinaus funktioniert dieser Ansatz nur für Windows Store-Lösungen!
Hinweis: Diese Methode ist nicht threadsicher, wenn Sie Ihre Methode innerhalb einer anderen asynchronen Methode aufrufen (gemäß den Kommentaren von @Servy).
quelle
CancellationToken
für meine Lösung implementieren .Warten Sie in Ihrem Code zum ersten Mal auf die Ausführung der Aufgabe, aber Sie haben sie noch nicht gestartet, sodass sie auf unbestimmte Zeit wartet. Versuche dies:
Bearbeiten:
Sie sagen, dass Sie eine Ausnahme bekommen. Bitte posten Sie weitere Details, einschließlich Stack-Trace.
Mono enthält den folgenden Testfall:
Überprüfen Sie, ob dies für Sie funktioniert. Wenn dies nicht der Fall ist, obwohl dies sehr unwahrscheinlich ist, haben Sie möglicherweise einen seltsamen Build von Async CTP. Wenn dies funktioniert, möchten Sie möglicherweise untersuchen, was genau der Compiler generiert und wie sich die
Task
Instanziierung von diesem Beispiel unterscheidet.Edit # 2:
Ich habe mit Reflektor , dass die Ausnahme Sie tritt beschrieben , wenn
m_action
istnull
. Das ist etwas seltsam, aber ich bin kein Experte für Async CTP. Wie gesagt, Sie sollten Ihren Code dekompilieren und sehen, wie genauTask
instanziiert wird, wie esm_action
kommtnull
.PS Was ist mit den gelegentlichen Abstimmungen los? Möchtest du das näher erläutern?
quelle
RunSynchronously may not be called on a task unbound to a delegate
. Google ist keine Hilfe, da alle Ergebnisse dafür auf Chinesisch sind ...await
Schlüsselwort verwendet wird. Die in meinem früheren Kommentar veröffentlichte Ausnahme ist die Ausnahme, die ich erhalte, obwohl es eine der wenigen ist, für die ich nicht googeln und eine Ursache oder Lösung finden kann.async
undasync
Schlüsselwörter sind nichts anderes als Syntaxzucker. Compiler generiert Code erstellenTask<Customer>
inGetCustomers()
so das ist , wo ich zum ersten Mal aussehen würde. Als Ausnahme haben Sie nur eine Ausnahmemeldung gepostet, die ohne Ausnahmetyp und Stapelverfolgung unbrauchbar ist. Rufen Sie die Ausnahmemethode aufToString()
und veröffentlichen Sie die Ausgabe in der Frage.Getestet in .Net 4.6. Es kann auch einen Deadlock vermeiden.
Für die Rückgabe der asynchronen Methode
Task
.Für die Rückgabe der asynchronen Methode
Task<T>
Bearbeiten :
Wenn der Aufrufer im Thread-Pool-Thread ausgeführt wird (oder sich der Aufrufer auch in einer Aufgabe befindet), kann dies in bestimmten Situationen immer noch zu einem Deadlock führen.
quelle
Result
ist perfekt für den Job, wenn Sie einen synchronen Anruf wünschen, und ansonsten geradezu gefährlich. Der NameResult
oder die Intelligenz enthält nichts, wasResult
darauf hinweist, dass es sich um einen blockierenden Anruf handelt. Es sollte wirklich umbenannt werden.Verwenden Sie den folgenden Code-Snip
quelle
Warum nicht einen Anruf erstellen wie:
das ist nicht asynchron.
quelle
Diese Antwort richtet sich an alle, die WPF für .NET 4.5 verwenden.
Wenn Sie versuchen,
Task.Run()
auf dem GUI-Thread auszuführen ,task.Wait()
bleibt dies auf unbestimmte Zeit hängen, wenn Sie dasasync
Schlüsselwort nicht in Ihrer Funktionsdefinition haben.Diese Erweiterungsmethode löst das Problem, indem überprüft wird, ob sich der GUI-Thread befindet, und wenn ja, die Aufgabe im WPF-Dispatcher-Thread ausgeführt wird.
Diese Klasse kann als Bindeglied zwischen der asynchronen / wartenden Welt und der nicht asynchronen / wartenden Welt fungieren, wenn dies unvermeidbar ist, z. B. MVVM-Eigenschaften oder Abhängigkeiten von anderen APIs, die keine asynchrone / wartende Welt verwenden.
quelle
Einfach anrufen
.Result;
oder.Wait()
ein Risiko für Deadlocks darstellen, wie viele in Kommentaren gesagt haben. Da die meisten von uns Oneliner mögen, können Sie diese für verwenden.Net 4.5<
Erfassen eines Werts über eine asynchrone Methode:
Synchrones Aufrufen einer asynchronen Methode
Durch die Verwendung von treten keine Deadlock-Probleme auf
Task.Run
.Quelle:
https://stackoverflow.com/a/32429753/3850405
quelle
Ich denke, die folgende Hilfsmethode könnte das Problem ebenfalls lösen.
Kann folgendermaßen verwendet werden:
quelle
Das funktioniert bei mir
quelle
Ich habe festgestellt, dass SpinWait dafür ziemlich gut funktioniert.
Der obige Ansatz muss nicht .Result oder .Wait () verwenden. Außerdem können Sie ein Zeitlimit festlegen, damit Sie nicht für immer hängen bleiben, falls die Aufgabe nie abgeschlossen wird.
quelle
Auf wp8:
Wickeln Sie es ein:
Nennen:
quelle
quelle
Oder Sie könnten einfach gehen mit:
Stellen Sie zum Kompilieren sicher, dass Sie auf die Erweiterungsbaugruppe verweisen:
quelle
Versuchen Sie folgenden Code, der für mich funktioniert:
quelle