2009-02-03 8 views
28

En una aplicación de Windows Forms cuál es el impacto de llamar Thread.Sleep(1) como se ilustra en el siguiente código:¿Cuál es el impacto de Thread.Sleep (1) en C#?

public Constructor() 
{ 
    Thread thread = new Thread(Task); 
    thread.IsBackground = true; 
    thread.Start(); 
} 

private void Task() 
{ 
    while (true) 
    { 
     // do something 
     Thread.Sleep(1); 
    } 
} 

Será este hilo cerdo toda la CPU disponible?

¿Qué técnicas de creación de perfiles puedo usar para medir el uso de la CPU de este subproceso (que no sea el administrador de tareas)?

+0

Todas las respuestas hasta el momento indican que el efecto sería insignificante, pero ¿puede dar alguna aclaración sobre lo que está tratando de lograr con esto? – JMD

+0

Estoy tratando de ver si mi aplicación GUI pasa todo el tiempo en este hilo debido a la corta demora de 1 ms. –

Respuesta

43

Como se indicó, su bucle no enganchará la CPU.

Pero cuidado: Windows es no un sistema operativo en tiempo real, por lo que no obtener 1.000 estelas por segundo desde Thread.Sleep (1). Si no ha utilizado timeBeginPeriod para establecer su resolución mínima, se despertará cada 15 ms. Incluso después de establecer la resolución mínima en 1 ms, solo se despertará cada 3-4 ms.

Para obtener la granularidad del temporizador de nivel de milisegundos, debe utilizar el temporizador multimedia Win32 (C# wrapper).

+0

¿Podría dar un ejemplo de configuración de timeBeginPeriod en C#? –

+3

http://www.pinvoke.net/default.aspx/winmm.timeBeginPeriod De acuerdo con el documento de MSDN, timeBeginPeriod debe coincidir con una llamada timeEndPeriod. También tenga en cuenta que "Esta función afecta a una configuración global de Windows". y puede afectar el rendimiento del sistema. –

28

No, no va a acaparar la CPU, solo detendrá el hilo durante al menos ese largo. Mientras el hilo está en pausa, el sistema operativo puede programar otro hilo no relacionado para hacer uso del procesador.

+1

Sin embargo, sería necesario un montón de tiempo de CPU innecesariamente. –

+0

@Joel Cómo/por qué habría más tiempo que mientras (verdadero) {i ++; } o es esencialmente el mismo en términos de uso de CPU? – DevinB

+8

En una CPU moderna, un sueño de 1ms es una eternidad en comparación con hacer i ++. – Serguei

2

No, no encerrará toda la CPU disponible, porque el programador del SO cambiará el hilo que duerme cuando otro hilo tiene trabajo por hacer.

2

No, no lo hará. Apenas lo verás En algún lugar menos de 1000 veces por segundo este hilo se despertará y no hará casi nada antes de volver a dormir.

Editar:

que tenía que comprobar. Ejecutando en Java 1.5, esta prueba

@Test 
public void testSpeed() throws InterruptedException { 
    long currentTime = System.currentTimeMillis(); 
    int i = 0; 
     while (i < 1000) 
     { 
      Thread.sleep(1); 
      i++; 
     } 
    System.out.println("Executed in " + (System.currentTimeMillis() - currentTime)); 
} 

Corregí aproximadamente 500 duermen por segundo en mi máquina de 3 ghz. Supongo que C# debería ser bastante similar. Supongo que alguien informará con números de C# para este punto de referencia intensamente importante en el mundo real. No hubo uso de CPU observable, por cierto.

+0

Dudo que suceda incluso tan a menudo: el argumento para dormir es un tiempo mínimo, y el cambio de contexto lleva demasiado tiempo para obtener muchos de todos modos. –

+0

En los sistemas multinúcleo modernos 1ms es un tiempo muy largo. Me pregunto cómo funcionaría realmente este ciclo. – krosenvold

0

Un hilo puede, como máximo, encerrar una CPU (lógica) a la vez. Y un sueño de 1ms no será acaparador. No te preocupes

19

Thread.Sleep (1) como se indica no enganchará la CPU.

Esto es lo que sucede cuando un hilo duerme (más o menos):

  • Thread.Sleep se traduce en una llamada al sistema, que a su vez desencadena una trampa (una interrupción que permite al sistema operativo para tomar control)
  • El sistema operativo detecta la llamada en suspensión y marca el hilo como bloqueado.
  • Internamente, el sistema operativo mantiene una lista de hilos que deben ser reactivados y cuándo debería suceder.
  • Como el hilo ya no usa la CPU, el sistema operativo ...
  • Si el proceso primario no ha agotado todo su segmento de tiempo, el sistema operativo programará otra secuencia del proceso para su ejecución.
  • De lo contrario, otro proceso (o el proceso inactivo) comenzará a ejecutarse.
  • Cuando llegue el momento, el hilo se programará nuevamente para su ejecución, eso no significa que comenzará a ejecutarse automáticamente.

Como nota final, no sé exactamente lo que está haciendo, pero parece que está tratando de asumir el papel del programador, es decir, durmiendo para proporcionar a la CPU tiempo para hacer otras cosas ...

En algunos casos (muy pocos) de hecho podría estar bien, pero sobre todo se debe dejar que el programador haga su trabajo, es probable que sabe más que tú, y puede hacer el trabajo mejor que usted puede hacerlo.

4

Como mencionó Bob Nadler Thread.Sleep(1) no garantiza un tiempo de inactividad de 1ms.

Aquí hay un ejemplo usando el temporizador multimedia Win32 para forzar un descanso de 1 ms.

[DllImport("winmm.dll")] 
    internal static extern uint timeBeginPeriod(uint period); 
    [DllImport("winmm.dll")] 
    internal static extern uint timeEndPeriod(uint period); 

    timeBeginPeriod(1); 
    while(true) 
    { 
     Thread.Sleep(1); // will sleep 1ms every time 
    } 
    timeEndPeriod(1); 

Prueba esto en una aplicación C# interfaz gráfica de usuario, he encontrado que la aplicación utiliza alrededor del 50% de mi CPU.

Para mayor discusión sobre este tema véase el siguiente hilo del foro:

http://www.dotnet247.com/247reference/msgs/57/289291.aspx

3

Este es un viejo hilo que aparece en muchas de mis búsquedas, pero Win7 tiene un nuevo planificador y parece comportarse de manera diferente a la anterior.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace ConsoleApplication2 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      DateTime dtEnd = DateTime.Now.AddSeconds(1.0); 
      int i = 0; 
      while (DateTime.Now < dtEnd) 
      { 
       i++; 
       Thread.Sleep(1); 
      } 

      Console.WriteLine(i.ToString()); 

      i = 0; 
      long lStart = DateTime.Now.Ticks; 
      while (i++ < 1000) 
       Thread.Sleep(1); 

      long lTmp = (DateTime.Now.Ticks - lStart)/10000; 

      Console.WriteLine(lTmp.ToString()); 

      Console.Read(); 
     } 
    } 
} 

Con el código anterior, Mi primer resultado dio 946. Así, en el intervalo de tiempo de 1 segundo utilizando 1ms duerme, tengo 946 despertares. Eso es muy cerca de 1 ms.

La segunda parte pregunta cuánto tiempo lleva hacer 1000 eventos de sueño a 1 ms cada uno. Tengo 1034ms. De nuevo, casi 1ms.

Esto fue en un Core2Duo 1.8GHz + Win7 usando .Net 4.0

Editar: recordar, dormir (x) no significa despertador arriba en este momento, significa despiértame no antes de este tiempo . No está garantizado Aunque puede aumentar la prioridad del subproceso y Windows debe programar el subproceso antes de los subprocesos de menor prioridad.

+1

Un comentario para agregar sobre el programador Win 7. Ejecuté la publicación de ejemplo "espacio de nombres ConsoleApplication2" de Bengie e informó 65 y 15600 indicando aproximadamente ~ 15ms pasos. Este es un 3.33Mhx dual ejecutando .NET 3.5, Win 7. Lo extraño es que ayer tuve registros con algún código que mostraba sleep (1) mucho más cerca de 1ms como sus reclamos de publicación. Mi conclusión es que hay algún ajuste o configuración que ha cambiado en mi máquina, pero no puedo determinarlo. La misma respuesta en modos de depuración o liberación con o sin depurador. No usé el TimePeriod de inicio/finalización. Hay muy poca carga en la ma – crokusek

0

también echar un vistazo a esto: msdn forum

using System; 
using System.Diagnostics; 
using System.Runtime.InteropServices; 
using System.Threading; 

namespace Test 
{ 
    public static class Program 
    { 
     public static void Main(string[] args) 
     { 
      Stopwatch sw = new Stopwatch(); 

      for (int i = 0; i < 10; ++i) 
      { 
       sw.Reset(); 
       sw.Start(); 
       Thread.Sleep(50); 
       sw.Stop(); 

       Console.WriteLine("(default) Slept for " + sw.ElapsedMilliseconds); 

       TimeBeginPeriod(1); 
       sw.Reset(); 
       sw.Start(); 
       Thread.Sleep(50); 
       sw.Stop(); 
       TimeEndPeriod(1); 

       Console.WriteLine("(highres) Slept for " + sw.ElapsedMilliseconds + "\n"); 
      } 
     } 

     [DllImport("winmm.dll", EntryPoint="timeBeginPeriod", SetLastError=true)] 
     private static extern uint TimeBeginPeriod(uint uMilliseconds); 

     [DllImport("winmm.dll", EntryPoint="timeEndPeriod", SetLastError=true)] 
     private static extern uint TimeEndPeriod(uint uMilliseconds); 
    } 
} 
4

veces pequeñas del sueño deben ser evitados como un hilo renunciar a su porción de tiempo consigue un aumento de prioridad cuando resignaled, y que puede conducir a los interruptores de alto contexto. En una aplicación multiproceso/servidor, esto puede llevar a un efecto contundente ya que los hilos están batallando por el tiempo de la CPU. En cambio, confíe en funciones asincrónicas y objetos de sincronización como secciones críticas o mutexes/semáforos.

Cuestiones relacionadas