¿Cuál es la diferencia entre Invoke () y BeginInvoke ()

398

¿Me pregunto cuál es la diferencia entre BeginInvoke()y Invoke()son?

Principalmente para qué se usaría cada uno.

EDITAR: ¿Cuál es la diferencia entre crear un objeto de subprocesamiento e invocar invocar en eso y simplemente llamar BeginInvoke()a un delegado? ¿O son la misma cosa?

Nathan W
fuente

Respuestas:

568

¿Te refieres a Delegate.Invoke/ BeginInvokeo Control.Invoke/ BeginInvoke?

  • Delegate.Invoke: Se ejecuta sincrónicamente en el mismo hilo.
  • Delegate.BeginInvoke: Se ejecuta de forma asíncrona en un threadpoolhilo.
  • Control.Invoke: Se ejecuta en el subproceso de la interfaz de usuario, pero el subproceso de llamada espera su finalización antes de continuar.
  • Control.BeginInvoke: Se ejecuta en el subproceso de la interfaz de usuario y el subproceso de llamada no espera su finalización.

La respuesta de Tim menciona cuándo es posible que desee usar BeginInvoke, aunque Delegate.BeginInvokesospecho que estaba orientado principalmente a eso.

Para las aplicaciones de formularios Windows Forms, sugeriría que normalmente debería usar BeginInvoke. De esa manera, no necesita preocuparse por el punto muerto, por ejemplo, ¡pero debe comprender que la UI puede no haberse actualizado para la próxima vez que la mire! En particular, no debe modificar los datos que el subproceso de interfaz de usuario podría estar a punto de utilizar para fines de visualización. Por ejemplo, si tiene un Personcon FirstNamey LastNamepropiedades, y lo hizo:

person.FirstName = "Kevin"; // person is a shared reference
person.LastName = "Spacey";
control.BeginInvoke(UpdateName);
person.FirstName = "Keyser";
person.LastName = "Soze";

Entonces la interfaz de usuario puede terminar mostrando "Keyser Spacey". (Existe una posibilidad externa de que pueda mostrar "Kevin Soze" pero solo a través de la rareza del modelo de memoria).

Sin embargo, a menos que tenga este tipo de problema, Control.BeginInvokees más fácil hacerlo bien y evitará que su hilo de fondo tenga que esperar sin una buena razón. Tenga en cuenta que el equipo de Windows Forms ha garantizado que puede usarlo Control.BeginInvokede manera "dispare y olvide", es decir, sin tener que llamar EndInvoke. Esto no es cierto para las llamadas asíncronas en general: normalmente cada BeginXXX debe tener una llamada EndXXX correspondiente, generalmente en la devolución de llamada.

Jon Skeet
fuente
44
Entonces, ¿por qué ppl usaría Invoke sobre BeingInvoke? ¿No debería haber algunas ventajas sobre el uso de Invoke? ¿Ambos ejecutan procesos en segundo plano, solo que uno está en el mismo hilo y el otro en un hilo diferente?
yeeen
2
@ Jon: mientras estoy usando Dispatcher.BeginInvoke mi código funciona bien y en Dispatcher.Invoco mi aplicación haciéndome esperar unos segundos y luego inicializa todos los controles y luego se inicia. ¿Pueden ayudarme a averiguar exactamente en qué lugar me quedé atascado? ?
SharpUrBrain
66
@SharpUrBrain: Control.BeginInvoke es una especie de equivalente de Dispatcher.BeginInvoke, pero para WinForms (mientras que Dispatcher es para WPF y Silverlight).
Jon Skeet
44
@SharpUrBrain: sugeriría que haga una pregunta específica en lugar de continuar en los comentarios, y, por supuesto, compruebe si otra persona ya ha formulado la misma pregunta primero.
Jon Skeet
2
@AZ: Sí, por "en el subproceso de la interfaz de usuario" se refiere al "subproceso de la interfaz de usuario" particular que posee el identificador de ese control en particular. Por lo general, solo hay un subproceso de interfaz de usuario, pero es posible tener varios subprocesos de interfaz de usuario, y en las aplicaciones avanzadas hay razones por las que los querría. Técnicamente, cualquier hilo (¿normal?) Podría iniciar una bomba de mensajes de IU y convertirse en un hilo de UI, y más tarde podría apagar la bomba de mensajes y dejar de ser un hilo de UI. (Supongo que eso no es algo para probar en un hilo de threadpool).
Rob Parker
46

Sobre la base de la respuesta de Jon Skeet, hay momentos en que desea invocar a un delegado y esperar a que se complete su ejecución antes de que continúe el hilo actual. En esos casos, la llamada de invocación es lo que desea.

En aplicaciones de subprocesos múltiples, es posible que no desee que un subproceso espere que un delegado finalice la ejecución, especialmente si ese delegado realiza E / S (lo que podría hacer que el delegado y su subproceso se bloqueen).

En esos casos, BeginInvoke sería útil. Al llamarlo, le está diciendo al delegado que comience, pero luego su hilo es libre de hacer otras cosas en paralelo con el delegado.

El uso de BeginInvoke aumenta la complejidad de su código, pero hay momentos en que el rendimiento mejorado vale la pena.

Tim Stewart
fuente
27

La diferencia entre Control.Invoke()y Control.BeginInvoke()es,

  • BeginInvoke()programará la acción asincrónica en el hilo de la GUI. Cuando se programa la acción asincrónica, su código continúa. Algún tiempo después (no sabe exactamente cuándo) se ejecutará su acción asincrónica
  • Invoke() ejecutará su acción asincrónica (en el hilo de la GUI) y esperará hasta que su acción se haya completado.

Una conclusión lógica es que un delegado al que pasa Invoke()puede tener parámetros fuera o un valor de retorno, mientras que un delegado al que pasa BeginInvoke()no puede (debe usar EndInvoke para recuperar los resultados).

Sujit
fuente
20

Solo para dar un breve ejemplo de trabajo para ver el efecto de su diferencia

new Thread(foo).Start();

private void foo()
{
  this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
    (ThreadStart)delegate()
    {
        myTextBox.Text = "bing";
        Thread.Sleep(TimeSpan.FromSeconds(3));
    });
  MessageBox.Show("done");
}

Si usa BeginInvoke , MessageBox aparece simultáneamente a la actualización de texto. Si usa Invoke , MessageBox aparece después de 3 segundos de suspensión. Por lo tanto, muestra el efecto de una llamada asincrónica ( BeginInvoke ) y una síncrona ( Invoke ).

KMC
fuente
9

Delegate.BeginInvoke () pone en cola asíncronamente la llamada de un delegado y devuelve el control de inmediato. Cuando use Delegate.BeginInvoke (), debe llamar a Delegate.EndInvoke () en el método de devolución de llamada para obtener los resultados.

Delegate.Invoke () llama sincrónicamente al delegado en el mismo hilo.

Artículo de MSDN

Aaron Palmer
fuente
8

Simplemente agregue por qué y cuándo usar Invoke ().

Tanto Invoke () como BeginInvoke () reúnen el código que especifique en el hilo del despachador.

Pero a diferencia de BeginInvoke (), Invoke () detiene su hilo hasta que el despachador ejecuta su código. Es posible que desee utilizar Invoke () si necesita pausar una operación asincrónica hasta que el usuario haya proporcionado algún tipo de comentario.

Por ejemplo, puede llamar a Invoke () para ejecutar un fragmento de código que muestre un cuadro de diálogo Aceptar / Cancelar. Después de que el usuario hace clic en un botón y se completa su código ordenado, el método invoke () volverá y usted puede actuar según la respuesta del usuario.

Ver Pro WPF en C # capítulo 31

Ingako
fuente