traves - thread c# windows form
¿No es ciego usar InvokeRequired solo una mala práctica? (2)
Soy un programador novato, por lo que podría estar completamente equivocado aquí, pero este problema me molesta más de lo que debería.
Esto es en realidad un seguimiento de this pregunta.
La respuesta aceptada fue que tienes que llamar a InvokeRequired para evitar una sobrecarga, porque existe la posibilidad de que ya estés operando en el subproceso de la interfaz de usuario.
En teoría, estoy de acuerdo en que podría ahorrar algo de tiempo. Después de algunas pruebas, descubrí que usar Invoke toma aproximadamente el doble de tiempo en comparación con llamar a una operación normalmente (pruebas como configurar el texto de una etiqueta n veces, o colocar una cadena muy, muy grande en un RichTextBox).
¡Pero! Entonces hay práctica.
La documentación de MSDN dice:
Esta propiedad se puede usar para determinar si debe llamar a un método de invocación, lo que puede ser útil si no sabe qué subproceso posee un control.
En la mayoría de los casos, sabe cuándo intenta acceder a un control desde otro hilo. En realidad, la única situación en la que puedo pensar es cuando se accede al control desde un método que puede ser llamado tanto por el subproceso X como por el subproceso propietario. Y eso para mí es una situación muy poco probable.
E incluso si realmente no sabes qué subproceso intenta manipular el control, existe el hecho de que el subproceso de la interfaz de usuario no tiene que actualizarse con tanta frecuencia. Cualquier cosa entre 25-30 fps debería estar bien para su GUI. Y la mayoría de los cambios realizados en los controles de IU tardan mucho menos de milisegundos en realizarse.
Por lo tanto, si lo comprendo correctamente, el único escenario en el que debe verificar si se requiere una invocación es cuando no sabe qué subproceso está accediendo al control y cuando la actualización de la GUI tarda más de unos 40 ms en finalizar.
Luego está la respuesta a this pregunta que hice en http://programmers.stackexchange.com . Lo que indica que no debería estar ocupado con una optimización prematura cuando no la necesita. Especialmente si sacrifica la legibilidad del código.
Entonces, esto me lleva a mi pregunta: ¿no debería simplemente usar invocar cuando sabe que un hilo diferente accede a un control, y solo cuando sabe que su hilo de interfaz de usuario puede acceder a ese fragmento de código y encuentra que debería ejecutarse más rápido, que ¿Debería comprobar si se requiere una invocación?
PD: después de revisar mi pregunta, realmente suena como si estuviera despotricando. Pero en realidad solo siento curiosidad por el hecho de que InvokeRequired está aparentemente sobreutilizado por muchos programadores con más experiencia que yo.
En la práctica, las personas tienden a llamar al mismo método tanto desde el hilo externo como desde el propietario. El patrón habitual es que el método en sí mismo determina si el hilo es el hilo propietario. Si es así, ejecuta el código de seguimiento. Si no es así, el método se llama a sí mismo usando Invoke
esta vez.
Una de las ventajas de esto es que hace que el código sea más compacto , ya que tiene un método relacionado con la operación en lugar de dos.
Otro beneficio, y probablemente más importante, es que reduce la posibilidad de que se genere la excepción de subproceso. Si ambos métodos estuvieran disponibles en cualquier momento y ambos hilos pudieran elegir cualquiera de los dos, entonces habría una posibilidad de que un método aparentemente legítimo genere una excepción. Por otro lado, si solo hay un método que se adapta a la situación, proporciona una interfaz más segura .
Estás tomando las cosas fuera de contexto aquí. La primera pregunta this vinculó otra pregunta que específicamente fue sobre escribir un método seguro para subprocesos para acceder a un control de UI.
Si no necesita un acceso seguro para subprocesos a un control de UI, porque sabe que no lo actualizará desde otro subproceso, entonces ciertamente, no debería emplear esta técnica. Simplemente actualice su control de UI sin usar InvokeRequired
o Invoke
.
Por otro lado, si la llamada siempre se originará en un subproceso que no sea el subproceso de la interfaz de usuario, simplemente use Invoke
sin verificar primero el InvokeRequired
.
Esto lleva a tres reglas simples:
- Si actualiza el control solo desde el subproceso de la interfaz de usuario, no utilice
InvokeRequired
niInvoke
- Si actualiza el control solo desde un subproceso que no sea el subproceso de la interfaz de usuario, utilice solo
Invoke
. - Si actualiza el control desde el subproceso de la interfaz de usuario y otros subprocesos, use
Invoke
en combinación conInvokeRequired
.