2010-11-26 19 views
5

Quiero invocar un método que manipule un control en el subproceso de interfaz de usuario. Mi código funciona y quiero optimizarlo. Me refiero a esto resource on MSDN.
Según ahí, debemos hacerWinforms multihilo: ¿Está creando un nuevo delegado cada vez que se necesita invocar un método en el subproceso de interfaz de usuario?

public delegate void myDelegate(int anInteger, string aString); 
//... 
Label1.Invoke(new myDelegate(myMethod), new Object[] {1, "This is the string"}); 

Sería esto introducir un objeto delegado huérfanos (una pérdida de memoria), en cada llamada?

Cuando lo haría con una instancia estática del delegado, como a continuación y luego utilizar esta instancia en cada llamada para invocar:

private static _delegateInstance = new myDelegate(myMethod); 
//... 
Label1.Invoke(_delegateInstance , new Object[] {1, "This is the string"}); 

Sería ésta Hilo de seguridad? ¿Sería cierto que esto tiene un rendimiento ligeramente mejor, ya que la instancia de delegado solo se crea una vez?

Respuesta

1

¿Esto introduciría un objeto de delegado huérfano (una pérdida de memoria) en cada llamada?

No, no, no está mal.

Sin embargo, para evitar la creación de un delegado cada vez que se podría utilizar algunos de los existing (si el método tiene 2 parámetros de cadena y no ha de retorno):

Label1.Invoke.Invoke((Action<string, string>)myMethod, 
    new object[] { 1, "This is the string" }); 
+0

¡Gracias, esto lo hace muy bien! – Marcel

0

En primer lugar, C# es un lenguaje administrado, por lo tanto, no hay pérdidas de memoria. Nunca.

En segundo lugar, no tome MSDN como la decisión final cuando está tratando de optimizar. Muchos fragmentos de código que encuentras allí ni siquiera cumplen con los estándares de codificación de MS (incluso los más básicos) o incluso el sentido común.

En tercer lugar, la línea: private _delegateInstance = new myDelegate (myMetho); no crea nada estático Crea una variable que contiene la nueva instancia devuelta desde new myDelegate (myMethod).

Por último, el uso de la palabra clave "nueva" definitivamente creará un nuevo objeto myDelegate en cada llamada, así como un comportamiento muy diferente del segundo fragmento de código que escribió, pero en algunos casos esto es obligatorio.

Probablemente desee utilizar la segunda opción que escribió, pero la verdad es que debe tomarse el tiempo y leer \ aprender algo más sobre los delegados y C# en general.

Buena suerte y disfrute.

+4

¡Estás equivocado, las pérdidas de memoria son muy posibles en C# /. Net! – Jaster

+0

I segundo Jaster. Se limpiarían en la salida de la aplicación, pero durante el tiempo de ejecución es muy posible tener asignados objetos innecesarios. – Marcel

+0

Gracias por mencionar lo estático. Cambié el código de ejemplo. – Marcel

2

Las dos respuestas anteriores le han dado alguna información. Hay un buen artículo here si desea obtener información más detallada.

Ambos métodos son seguros para la ejecución de subprocesos, porque en el tiempo de invocación el grupo de subprocesos asigna un subproceso para cada llamada. Existe la posibilidad de bloqueo, pero si lees ese artículo hay formas de evitarlo.

Además, debe tener en cuenta que .Net maneja el subproceso de interfaz de usuario de forma ligeramente diferente. Si está tratando con WPF, tendrá que tener en cuenta al despachador. Ver here.

En última instancia, no estoy seguro de que obtendría un aumento de rendimiento masivo con el segundo código, por lo que me inclinaría a seguir con el primero.

N.

+0

¡Gracias por el enlace al artículo de delegado bueno! – Marcel

+0

Recuerde, que "arriba" es relativo, y en SO ¡cambia con el tiempo! :-) – Marcel

+0

Gracias, se olvidó de eso;) – Nick

2

Un "patrón" alternativa (si se le puede llamar que) es tener el método simplemente invocar sí mismo, asumiendo que es parte de una clase Form:

void myMethod(int anInteger, string aString) 
{ 
    if (InvokeRequired) 
    { 
     Invoke(new Action<int,string>(myMethod),anInteger,aString); 
     return; 
    } 

    Label1.Text = aString; 
} 

El Action el objeto permanecerá en el montón, cambiará la propiedad del texto, luego será GC en el próximo barrido. No puedo ver que sea un golpe de rendimiento a menos que el método se atenga a algunos recursos externos, como un identificador a IE, archivo, etc.

+0

Gracias por comentar sobre la recolección de basura. – Marcel

0

Su primer fragmento crea una instancia de objeto delegado cada vez. Esto no causa ninguna fuga, pero aumenta la cantidad de objetos que se deben recolectar como basura.

Su segundo fragmento no crea los objetos de delegado cada vez, pero es imposible (suponiendo que myMethod es un método de instancia) ya que los miembros no pueden usar miembros de instancia.

Darin Dimitrov está equivocado: su código usa el delegado de Acción existente en lugar de uno personalizado, pero aún crea un objeto de delegado de Acción cada vez (a diferencia de su segundo fragmento). Por lo tanto, podría usar el siguiente código:

private Action<int, string> _delegateInstance = myMethod; 
//... 
Label1.Invoke(_delegateInstance , new Object[] {1, "This is the string"}); 
Cuestiones relacionadas