2009-11-04 6 views
8

No estoy seguro de qué estrategia adoptar ... Me estoy enfocando en que mi operación se complete, pero también me gustaría mantener los problemas de rendimiento en un mínimo también. ..hay un método llamado Execute() que tiene que esperar (se ejecuta de forma síncrona) hasta que se complete una operación. Esta operación ocurre en otro hilo. Hay 2 maneras de implementar la misma cosa ...Para hacer una elección entre ManualResetEvent o Thread.Sleep()

Al usar ManualResetEvent

void Execute() 
{ 
    taskHandle = new ManualResetEvent(false); 
    . 
    . 
    //delegate task to another thread 
    . 
    . 
    taskHandle.WaitOne(); 
} 

O

Mediante el uso de un simple, mientras que construir

void Execute() 
{ 
    . 
    . 
    //delegate task to another thread 
    . 
    . 
    while (!JobCompleted) 
     Thread.Sleep(1000); 
} 

¿Cuál de los dos enfoques ¿Debería adoptar ... por qué?

EDITAR:

Q2. ¿Qué pasa si acabo de tener un edificio vacío mientras? Cual es la diferencia...?

while(!JobCompleted); 

EDIT: (algo que se reunieron antes)

http://www.yoda.arachsys.com/csharp/threads/waithandles.shtml - En este artículo se dice manualresets son comparativamente más lento, ya que salen de código administrado y de regreso en ...

+0

Solo quiero señalar el uso de Thread.Sleep (0). Especifique cero (0) para indicar que este hilo debe suspenderse para permitir la ejecución de otros hilos en espera. En este caso, Sleep (0) es mejor que Sleep (1000), pero usar WaitHandle es aún más apropiado. –

+4

El ciclo while vacío es básicamente un spinwait, consumirá completamente una CPU. No recomendado. – nitzmahone

Respuesta

13

Por curiosidad, ¿por qué ManualResetEvent y no AutoResetEvent? De cualquier manera, vaya con la primitiva OS sobre un enfoque de sueño-verificación-sueño.

También es posible usar una cerradura Monitor (ya sea de forma explícita a través Monitor.Enter y Monitor.Exit, o por medio de un bloque lock), pero el enfoque debe basarse en lo que está haciendo en realidad; si se trata de un escenario de "solo hay una de estas cosas y necesito acceso exclusivo", entonces use un bloqueo Monitor. Si es "Tengo que esperar hasta , el otro hilo termina por razones distintas al acceso a los recursos", luego utilice AutoResetEvent o ManualResetEvent.

Las sugerencias para utilizar Thread.Join son buenas si (y sólo si)

  1. Usted tiene acceso a otro objeto Thread
  2. No desea ejecutar hasta que el otro subproceso termina .

Si bien no es cierto (que no tienen acceso, o el otro hilo no va a terminar, se acaba de señalar un "fuera de peligro"), entonces Thread.Join no es viable.

La peor opción es

while(!JobCompleted);

Como que va a atar el procesador con cheques innecesarias de la variable sin ninguna pausa entre ellos. Sí, bloqueará el hilo hasta que la operación se complete, pero se maximizará el uso de la CPU (o al menos el valor de un único núcleo).

+0

lea alguna vez que el manual restablece el trabajo en modo kernel ... de ser así, debería haber una sobrecarga de rendimiento, ¿no? PD: He editado la pregunta de nuevo ... – deostroll

+0

Usted sugiere ir con la primitiva del sistema operativo, pero realmente debería explicar por qué. – Gigi

2

Si usted tiene acceso a el objeto Thread original, o puede obtener ese acceso, es mejor que use Thread.Join().

Editar: También, si esto está teniendo lugar en una interfaz gráfica de usuario como Windows Forms o WPF, es posible que desee considerar el uso BackgroundWorker

+0

No tengo acceso al objeto de subproceso ... – deostroll

+0

Luego use ManualResetEvent como @nitzmahone sugiere. O encuentra una manera de obtener ese hilo. El único inconveniente con el uso de ManualResetEvent es que tanto la persona que llama como el trabajador tienen que usarlo, creando una dependencia posiblemente no deseada. – Randolpho

+0

@Randolpho. ¿No tendrían ambos métodos que compartir recursos para poderse señalar entre ellos? En el caso del ciclo while, ambos hilos deben conocer el booleano 'JobCompleted'. – rocka

4

El evento hace un uso más eficiente de la Procesadores- usted no está teniendo para despertar a los padre de rosca hasta la encuesta. El kernel lo despertará cuando se desate el evento.

+0

Pero no son costosos los eventos manuales en comparación con la otra construcción. Yo uso .net 2.0. Lea en algún lugar que el restablecimiento manual funciona en el modo kernel, mientras que las alternativas de su monitor funcionan en modo de usuario ... ¡así que hay un recargo extra debido al cambio de modo ...! ¿Es esto cierto? – deostroll

+0

Son más caros de crear que los monitores, pero también son más completos. Depende de la frecuencia con que los está creando. Si está buscando ejecutar miles de estos por segundo, un enfoque más ligero sería mejor. – nitzmahone

2

La principal desventaja de usar Thread.Sleep() es que está tomando una decisión sobre cuánto tiempo esperará el subproceso. La operación que está esperando puede tomar más o menos vez, y en general, es muy difícil cuantificar con precisión ese tiempo. Si el hilo duerme demasiado, entonces no está haciendo el mejor uso de los recursos del sistema.

Para ser óptimo, debe usar ManualResetEvent (o AutoResetEvent) para que su hilo se reanude tan pronto como finalice la operación dependiente.

0

Ambos enfoques hacen básicamente lo mismo. Sin embargo, el ciclo while es un poco más explícito, ya que puede especificar el tiempo de suspensión. Aunque usaría las clases XXXResetEvent que deben usarse en el escenario en el que trabaja. Asumiría que las clases de subprocesos se implementarían ahora o más tarde con un código de subprocesamiento más robusto para manejar quizás la afinidad de subprocesos en procesadores multinúcleo.

+0

A ManualResetEvent se comporta de forma bastante diferente que el sondeo periódico. –

1

ManualResetEvent es definitivamente el camino a seguir.

Desde el fragmento de código que ha proporcionado, parece que está delegando la ejecución en su método Execute. Si este es el caso, y usted solo está delegando una sola tarea, ¿por qué está delegando a otro hilo en absoluto si tiene que esperar la respuesta? También puede ejecutar el proceso sincrónicamente.

1

manualresets son comparativamente más lento, ya que salen de código administrado y la espalda en ..

Ellos son probablemente más lento que decir una Wait/Pulse combo, que se debe utilizar aquí en mi opinión. Pero Manual/AutoResetEvents será mucho más rápido que cualquier Thread.Sleep(x) que haga, incluso si elige x = 1. E incluso si reduce la resolución del temporizador de Windows a 1 ms.

¿Qué pasa si acabo de tener un vacío mientras contruct? Cual es la diferencia...?

Entonces, un núcleo girará al 100% hasta que la condición se vuelve verdadera, robando tiempo de otros temas que en vez podrían utilizar para hacer algo útil, como el cálculo de los marcos para "Angry Birds" - o la CPU podría simplemente refrésquese un poco, retrasando los efectos nefastos del calentamiento global durante algunos nanosegundos adicionales.

Cuestiones relacionadas