Gibt es eine gute Übung (Muster), asynchrone Aufrufe synchron zu machen?
Ich habe eine Bibliothek von Drittanbietern, deren Methoden alle asynchron sind, um das Ergebnis von fast jeder Methode zu erhalten, die Sie einem Ereignis zuhören müssen, das einen Zusammenhang damit bringen wird.
im Grunde sieht es so aus:
was ich brauche, ist Code nach BeginSomething auszuführen, wenn es wirklich abgeschlossen ist (also nachdem OnBeginSomethingCompleted ausgelöst wurde). Es ist sehr unpraktisch, die Reaktion in diesem Fall zu bewältigen.
Der einzige Weg, an den ich denken könnte, ist eine Thread.Sleep-Schleife zu starten und zu warten, bis ein Feld auf dem Formular aktualisiert wird, aber es sieht nicht nach sehr eleganter Lösung aus.
Ich verwende .net 4.0.
Sie könnten die Hauptklasse ableiten und eine synchrone Version der Operation bereitstellen. Wenn Unterklassen keine Option sind, können Sie eine Erweiterungsmethode erstellen. So könnten die Dinge aussehen.
%Vor%Aktualisierung:
Ich hätte darauf hinweisen sollen, dass dies in einigen Fällen problematisch sein könnte. Betrachten Sie dieses Beispiel.
%Vor% Es sollte offensichtlich sein, dass das handler
in Something
das Ereignis OnBeginSomethingCompleted
vom vorherigen Aufruf an BeginSomething
erhalten könnte. Stellen Sie sicher, dass Sie sich davor schützen.
Verwende ein ManualResetEvent
. Erstellen Sie es in Ihrem Sync-Wrapper, und übergeben Sie es als Teil des Statusobjekts an den service.BeginSomething()
-Aufruf. Unmittelbar nach dem Aufruf, WaitOne()
, wird dies blockiert.
Im Ereignis service.OnBeginSomethingCompleted
wird es aus dem Statusobjekt extrahiert und gesetzt. Dadurch wird der Synchronisierungsaufruf freigegeben.
Wie bereits erwähnt, sollten Sie, wenn möglich ist, versuchen, Ihren eigenen Code asynchron zu machen. Wenn das nicht funktioniert, unterstützt Ihre Bibliothek von Drittanbietern das standardmäßige asynchrone Muster BeginXXX
, EndXXX
? Wenn ja, würde die Verwendung der TPL Ihnen die Arbeit erleichtern. Ihr Code sieht etwa so aus:
Die spezifische Überladung, die Sie verwenden möchten, hängt davon ab, wie viele Parameter Sie übergeben müssen. Sie können die Liste hier sehen.
Wenn BeginSomething()
eine IAsyncResult
zurückgibt (wie die .BeginInvoke
eines Delegierten), können Sie die WaitHandle
von dieser erhalten:
Wenn Sie den Ereignishandler nach dem Start des Async-Prozesses zuweisen, führen Sie übrigens eine Race-Bedingung ein, bei der der Async-Aufruf abgeschlossen werden kann, bevor das Ereignis registriert wird, sodass er nie ausgelöst wird.
Vielleicht möchten Sie sich Reaktive Erweiterungen
ansehen Mit Rx können Sie das im Grunde in ein 'Ereignis' einbinden - das tun etwas wie someClass.SomeEvent.Subscribe(d=>...)
, um mit etwas Lambda-Ausdruck zu subskribieren, um zu handhaben, was Sie brauchen. Verwenden Sie auch ObserveOn
, um es auf dem GUI-Thread zu behandeln (siehe die Details, dies ist nur ein Hinweis).
Andere Option ist die Verwendung von async await
(das jetzt für die Verwendung mit VS 2010 verfügbar ist).
hoffe das hilft
HINWEIS: Rx haben eine native Unterstützung für asynchrone Methoden und verwandeln sie in Rx-Ereignisse mit ziemlich genau einem Aufruf. Werfen Sie einen Blick auf Observable.FromAsyncPattern
FromAsyncPattern
Der allgemeine Trend der modernen Softwareentwicklung (auch auf Windows-Plattformen) besteht darin, asynchron zu laufen.
Wenn der Code mehr als 50 ms lang ist, muss er eigentlich asynchron sein.
Ich würde also nicht vorschlagen, den Thread zu blockieren, sondern stattdessen von dieser Bibliothek zu profitieren und dem Benutzer eine gut aussehende Animation zu liefern, die sagt: "Warte, Antwort kommend" oder so etwas oder eine Fortschrittsanzeige.
Kurz gesagt, blockiere den Thread nicht, informiere einen Benutzer darüber, was in der App passiert und lasse ihn asynchron.
Diese Lösung ähnelt der von Brian Gideon, aber ich denke ein bisschen sauberer für das, was Sie versuchen zu tun. Es verwendet das Monitor-Objekt, um den aufrufenden Thread zu warten, bis das Completed-Ereignis ausgelöst wird.
%Vor%Tags und Links .net c# .net-4.0 design-patterns asynchronous