Asynchrone Aufrufe in synchrone konvertieren

8

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:

%Vor%

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.

    
Georgy Smirnov 12.04.2012, 13:25
quelle

7 Antworten

8

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.

    
Brian Gideon 12.04.2012, 13:40
quelle
2

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.

    
Eugen Rieck 12.04.2012 13:31
quelle
2

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:

%Vor%

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.

    
Adam Robinson 12.04.2012 13:30
quelle
1

Wenn BeginSomething() eine IAsyncResult zurückgibt (wie die .BeginInvoke eines Delegierten), können Sie die WaitHandle von dieser erhalten:

%Vor%

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.

    
Steve Czetty 12.04.2012 13:34
quelle
1

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

    
NSGaga 12.04.2012 13:32
quelle
0

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.

    
Tigran 12.04.2012 13:29
quelle
0

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%     
Mark Meuer 21.09.2013 18:43
quelle