2009-02-10 11 views

Respuesta

53

Delegate.EndInvoke se documenta como llamarás esta (es decir, es necesario - fugas demás suceda) - a partir msdn:

Nota Importante

No importa qué técnica use, siempre llame a EndInvoke para completar su asincrónico c todas.

Control.EndInvoke está bien ignorar para el fuego y olvida métodos - desde msdn:

Puede llamar EndInvoke para recuperar el valor retorno del delegado, si NECESARIO, pero esto no es requerido.

Sin embargo - si está utilizando Delegate.BeginInvoke y no desea que el resultado, considere el uso de ThreadPool.QueueUserWorkItem lugar - que va a hacer la vida mucho más fácil, y evitar el dolor de IAsyncResult etc.

+0

Gracias Marc, eso es lo que motivó la pregunta: estaba mirando a través de Richter y noté QueueUserWorkItem, y pensé "espera, por qué estoy usando BeginInvoke/EndInvoke en otro lugar". – endian

+0

@endian - de hecho: la mayoría del uso de BeginInvoke se puede hacer más simplemente con ThreadPool; el BeginInvoke es quizás útil para hacer algunas cosas y reunirlas de nuevo después ... –

+0

Enlightened. ¡Gracias! – rpattabi

18

EndInvoke no es opcional.

Más información here

+0

Gracias Luca - respuesta aceptada. – endian

+1

... para delegados, al menos ;-p –

+6

desde su enlace: "La única excepción documentada a la regla de la que soy consciente es en Windows Forms, donde se le permite oficialmente llamar a Control.BeginInvoke sin molestarse en llama a Control.EndInvoke ". – Avram

9

Y llamada EndInvoke no es una llamada opcional, es una parte del contrato. Si llama a BeginInvoke, debe llamar a EndInvoke.

Ejemplo clásico de por qué es necesario. Es muy posible que IAsyncResult devuelto por BeginInvoke haya asignado recursos asociados. Más comúnmente es una especie de WaitHandle. Como IAsyncResult no implementa IDisposable, se debe elegir otro lugar para liberar los recursos. El único lugar para hacerlo es EndInvoke.

Discuto brevemente este problema en la siguiente publicación del blog.

http://blogs.msdn.com/jaredpar/archive/2008/01/07/isynchronizeinvoke-now.aspx

+0

Gracias Jared, muy apreciado. – endian

4

EndInvoke no es opcional, ya que es el lugar donde se lanzan excepciones si algo ha ido mal en el procesamiento asincrónico.

De todos modos no debería haber ninguna fuga porque si el IAsyncResult está llevando a cabo algún recurso nativo que debe implementar correctamente IDisposable y disponer dichos recursos cuando el GC llama a su finalizador.

2

Es solo opcional si no le importa que la memoria de su programa crezca demasiado. El problema es que el GC se mantiene en todas las referencias en su hilo, porque es posible que desee llamar a EndInvoke en algún momento. Me gustaría ir con la respuesta de Marc, el grupo de temas te hará la vida más fácil. Sin embargo, debes tener cuidado si generas hilos de tus hilos, ya que está limitado en la cantidad de hilos que puede girar.

3

No es opcional porque llamar a BeginInvoke utiliza un WaitHandle que a su vez hace uso de un objeto kernel que mantiene un recuento de cuántas referencias se necesitan.Llamar a EndInvoke descarta con gracia el identificador que disminuye ese contador en el objeto kernel y cuando ese conteo llega a cero, el administrador de objetos del kernel lo destruirá.

2

Cada respuesta en esta publicación dice que EndInvoke() no es opcional. Sin embargo, encontré el siguiente comentario altamente calificado que es la respuesta aceptada en este hilo SO:

"Tenga en cuenta que el equipo de Windows Forms ha garantizado que puede usar Control.BeginInvoke de una manera 'disparar y olvidar' - es decir, sin siempre llamando a EndInvoke. Esto no ocurre con las llamadas asincrónicas en general: normalmente cada BeginXXX debe tener una llamada EndXXX correspondiente, generalmente en la devolución de llamada ".

What's the difference between Invoke() and BeginInvoke()

+0

En mi humilde opinión, es una lástima que 'Control.BeginInvoke' y' Delegate.BeginInvoke' compartan el mismo nombre, ya que tienen una semántica totalmente diferente; a decir verdad, tengo curiosidad sobre por qué los tipos de delegado definen 'BeginInvoke' como un método de instancia, en lugar de tener' Delegate.Bind (params) 'devolver un' MethodInvoker' [delegado de cero argumentos] que invocaría al delegado con los parámetros especificados, y que podrían pasarse a, por ejemplo, un método 'ThreadPool.BeginInvoke'. – supercat

+0

+1 para esta importante distinción. El omnisciente comentario de Skeet (citado anteriormente) es muy relevante para quienes consideran situaciones Control.InvocarRequisitos. –