2010-10-24 7 views
5

Recientemente tuve una de esas entrevistas realmente malas, donde juegan buen policía/policía malo contigo. Todo lo que respondí no era lo suficientemente bueno para uno de ellos y mi confianza se reducía minuto a minuto. Su pregunta final que realmente me confundió fue la siguiente:Pregunta de entrevista: cuando Control.InvokeRequired utiliza Control.Invoke o Control.BeginInvoke?

si un control necesitaría InvokeRequired ¿habría alguna diferencia en hacer .Invoke o .BeginInvoke?

Déjame mostrarte un ejemplo, como yo lo entiendo:

public delegate string WorkLongDelegate(int i); 

var del = new WorkLongDelegate(WorkLong); 
var callback = new AsyncCallback(CallBack); 
del.BeginInvoke(3000, callback, del); 

public string WorkLong(int i) 
{ 
     Thread.Sleep(i); 
     return (string.Format("Work was done within {0} seconds.", i));    
} 

private void CallBack(IAsyncResult ar) 
{ 
    var del = (WorkLongDelegate) ar.AsyncState; 
    SetText2(del.EndInvoke(ar)); 
} 

private void SetText2(string s) 
{ 
    if(InvokeRequired) 
    { 
     // What is the difference between BeginInvoke and Invoke in below? 
     BeginInvoke(new MethodInvoker(() => textBox1.Text = s)); 
    } 
    else 
    { 
     textBox1.Text = s; 
    } 
} 

he mencionado que BeginInvoke lo haría de forma asíncrona, mientras invocación sería detener el hilo de interfaz de usuario hasta su ejecución. Pero eso no fue lo suficientemente bueno. No obstante, no entiendo la implicación de rendimiento aquí si utilicé una Invocación. ¿Puede alguien por favor aclararme?

Respuesta

15

Invoke no detiene el UI hilo. Bloquea el que llama al hilo para continuar hasta que se completa el subproceso de la interfaz de usuario.

Entonces, realmente, la pregunta es si desea que la operación de fondo continúe antes de que la UI haya terminado de actualizarse. Por lo general, creo que este es el caso, por ejemplo, si solo está entregando un informe de progreso a la IU, no quiere dejar de trabajar solo porque el hilo de la IU aún no se ha alcanzado.

Por otro lado, si es necesario ir a buscar algo del hilo de interfaz de usuario (que es bastante raro, es cierto), entonces es posible que desee utilizar Invoke lugar. Yo diría que debes usar BeginInvoke a menos que tengas una razón específica para usar Invoke. Pero de cualquier forma, debes entender la diferencia :)

+2

Debido a esto, 'Invoke' es vulnerable a interbloqueos dependiendo de la configuración de seguridad de subprocesos –

0

Naturalmente, si usa la versión de asnyc, su cadena de fondo puede continuar inmediatamente, sin esperar el cambio de contexto.

Normalmente, esto debería ser más rápido (para el hilo de fondo), de lo que yo entiendo.

5

Un caso de uso muy obvio para Invoke() es cuando necesitas invocar un método cuyo valor de retorno necesites. Solo Invoke() puede proporcionarle esto, devuelve Object, el valor de retorno del método.

En uno más débil es donde su hilo de trabajo está produciendo resultados a un ritmo mucho más rápido que el hilo de la interfaz de usuario puede mantenerse al día. El uso de Invoke() acelerará al trabajador y la lista de invocación no puede crecer sin límite. Sin embargo, esto no es más que una curita para un problema mayor, no tiene sentido actualizar la IU más rápido de lo que un humano puede percibir. Una vez cada 40 milisegundos se ve sin problemas para el ojo humano. Aún desea utilizar Invoke() si lleva demasiado tiempo el subproceso de UI para procesar la recopilación de resultados. Los signos clásicos de tener un problema como este es la congelación del hilo de la interfaz de usuario, no moverse para pintar y responder a los eventos de mouse y teclado, ya que está completamente abrumado por las solicitudes de invocación. Y el hilo de la interfaz de usuario no responde por un tiempo después de que el trabajador completó la ejecución, ocupado trabajando en la acumulación.

Otro caso es el bloqueo de requisitos para el objeto (s) que pasa a BeginInvoke(). No se requiere bloqueo cuando utiliza Invoke(), el subproceso de interfaz de usuario y el subproceso de trabajo no pueden acceder al objeto al mismo tiempo. No es el caso de BeginInvoke, sigue conduciendo y si el hilo sigue usando el mismo objeto, entonces debe proteger el objeto con un bloqueo tanto en el hilo de la IU como en el trabajador.Si ese bloqueo impide que el trabajador progrese, entonces también podría usar Invoke(). Todo esto es bastante raro, toma mucho tiempo para que el hilo principal comience a ejecutar al delegado. Y siempre es una buena idea crear una nueva instancia del objeto después de invocarlo para que no haya necesidad de bloquearlo.

Cuestiones relacionadas