2009-02-10 5 views

Antwort

17

http://blogs.msdn.com/cbrumme/archive/2003/07/14/51495.aspx

sagt:

„Eine überraschende Tatsache ist, dass dies auch, warum Delegate.BeginInvoke/ EndInvoke sind so langsam im Vergleich zu äquivalenten Techniken wie ThreadPool.QueueUserWorkItem (oder UnsafeQueueUserWorkItem Wenn Sie verstehen die Auswirkungen auf die Sicherheit und wollen wirklich effizient sein.) Die codepath für BeginInv oke/EndInvoke wandelt sich schnell in die allgemeine Nachricht Verarbeitungscode des allgemeinen Remoting-Signalwegs um. "

+0

Hmmm, danke, das ist interessant und sehr gruselig. Ich denke, ich werde einen BeginInvoke()/EndInvoke() Code zurücksetzen, der keine Rückgabewerte erfordert! – endian

21

Die Hauptsache ich mit QueueUserWorkItem denken kann, ist, dass Sie die WaitCallback Delegattyp verwenden, die sieht heikel, wenn Sie bereits eine SomeRandomDelegate Instanz und einige args haben. Die gute Nachricht ist, dass Sie dies mit einem Verschluss beheben:

ThreadPool.QueueUserWorkItem(
    delegate { someDelegate(arg1, arg2); } 
); 

Dieses Muster sichert Sie auch die richtige starke Typisierung bei der Kompilierung erhalten (im Gegensatz zu Übergabe eines object Zustand arg zu QueueUserWorkItem und es in der Zielmethode Gießen). Dieses Muster kann auch verwendet werden, wenn Methoden direkt aufrufen:

ThreadPool.QueueUserWorkItem(
    delegate { SomeMethod(arg1, arg2); } 
); 

Offensichtlich ohne ein EndInvoke Äquivalent, können Sie auch keinen Rückgabewert zurück, es sei denn Sie eine Methode aufrufen/raise ein Ereignis/etc am Ende von Ihrer Methode ... mit einer verwandten Anmerkung, müssen Sie mit exception handling vorsichtig sein.

+3

Begegnung mit diesem genauen Szenario war das erste Mal dachte ich mir: "Wow, ich liebe Verschlüsse. " –

+0

Wow, das ist ein super Tipp. Es fühlt sich an wie eine Boxing/Unboxing-Semantik, und ich kann mir vorstellen, dass es nicht teurer, in einem breiten Schema von Dingen ist. –

+0

Hoppla, technisch sollte es "delegate (object o)" oder ähnlich sein, damit der Code kompiliert wird, da QueueUserWorkItem eine Delegatesignatur erwartet, die mit WaitCallback übereinstimmt, d. H. Eine, die einen einzelnen Parameter vom Typ object enthält. –

-1

Es sollte keinen großen Unterschied geben, ich denke auch, dass die generierte BeginInvoke/EndInvoke für einen Delegaten den Thread-Pool ausführt.

-1

Es sollte keinen Leistungsunterschied geben, da sowohl Delegate.BeginInvoke als auch ThreadPool.QueueUserWorkItem in einem Threadpool-Thread ausgeführt werden.

Der größte Unterschied ist, dass wenn Sie BeginInvoke aufrufen, Sie EndInvoke irgendwann aufrufen müssen. Im Gegensatz dazu ist ThreadPool.QueueUserWorkItem "Feuer und vergessen". Das hat Vor- und Nachteile. Der Vorteil ist, dass Sie es vergessen können. Der Nachteil ist, dass Sie keine Möglichkeit haben, dies zu wissen, es sei denn, Sie fügen Ihren eigenen Synchronisations-/Benachrichtigungsmechanismus hinzu, wenn die Aufgabe abgeschlossen ist.

14

Die EndInvoke() ein nützliches, aber selten Verhalten erwähnt - es rethrows alle unbehandelten Ausnahmen, dass die Delegierten im Rahmen des ursprünglichen Thread erzeugt, so dass Sie die Ausnahmeverarbeitungslogik in den Hauptcode bewegen können.

Wenn Ihr Delegat über out/ref-Parameter verfügt, werden diese der EndInvoke() -Signatur hinzugefügt, damit Sie sie abrufen können, wenn die Ausführung der Methode abgeschlossen ist.

+0

vielen dank, das wusste ich nicht – endian

4

Wenn Sie ThreadPool aufrufen.QueueUserWorkItem, Ausnahmen, die im Arbeitselement ausgelöst werden, werden im Hintergrundthread nicht behandelt (es sei denn, Sie fangen sie explizit ab). In .Net 2 und höher wird Ihre AppDomain beendet.

Wenn Sie delegate.BeginInvoke() aufrufen, werden Ausnahmen in die Warteschlange gestellt, wenn EndInvoke() aufgerufen wird. Wenn Sie EndInvoke() nie aufrufen, sind die Ausnahmen im Wesentlichen Speicher "durchgesickert" (wie jeder andere Status, der von der asynchronen Operation nicht freigegeben wird).

Verwandte Themen