Thread.Sleep por menos de 1 milisegundo

Quiero llamar hilo de dormir con menos de 1 milisegundo. Leí que ni thread.Sleep ni Windows-OS lo admiten.

¿Cuál es la solución para eso?

Para todos los que se preguntan por qué necesito esto: estoy haciendo una prueba de estrés, y quiero saber cuántos mensajes puede manejar mi módulo por segundo. Entonces mi código es:

// Set the relative part of Second hat will be allocated for each message //For example: 5 messages - every message will get 200 miliseconds var quantum = 1000 / numOfMessages; for (var i = 0; i < numOfMessages; i++) { _bus.Publish(new MyMessage()); if (rate != 0) Thread.Sleep(quantum); } 

Estaré encantado de obtener su opinión al respecto.

No puedes hacer esto. Una sola llamada de suspensión por lo general se bloqueará durante mucho más de un milisegundo (depende del sistema operativo y del sistema, pero en mi experiencia, Thread.Sleep(1) tiende a bloquearse entre 12 y 15 ms).

Windows, en general, no está diseñado como un sistema operativo en tiempo real . Este tipo de control generalmente es imposible de lograr en las versiones normales (de escritorio / servidor) de Windows.

Lo más cerca que puede llegar es típicamente girar y comer ciclos de CPU hasta que haya alcanzado el tiempo de espera que desea (medido con un contador de alto rendimiento). Esto, sin embargo, es bastante horrible: se comerá una CPU completa, e incluso entonces, es probable que el SO le quite el control y a veces “duerma” más de 1 ms …

El código siguiente definitivamente ofrecerá una forma más precisa de locking, en lugar de llamar a Thread.Sleep(x); (aunque este método bloqueará el hilo, no lo pondrá a dormir ). A continuación, usamos la clase StopWatch para medir cuánto tiempo necesitamos para mantener el bucle y bloquear el hilo de llamada.

 using System.Diagnostics; private static void NOP(double durationSeconds) { var durationTicks = Math.Round(durationSeconds * Stopwatch.Frequency); var sw = Stopwatch.StartNew(); while (sw.ElapsedTicks < durationTicks) { } } 

Ejemplo de uso,

 private static void Main() { NOP(5); // Wait 5 seconds. Console.WriteLine("Hello World!"); Console.ReadLine(); } 

¿Por qué?
Por lo general, hay un número muy limitado de CPU y núcleos en una máquina: solo obtendrá un número pequeño si las unidades de ejecución son independientes.

De las otras manos hay una cantidad de procesos y muchos más hilos. Cada subproceso requiere un poco de tiempo de procesador, que es asignado internamente por los procesos centrales de Windows. Por lo general, Windows bloquea todos los hilos y da una cierta cantidad de tiempo de núcleo de la CPU a hilos específicos, luego cambia el contexto a otros hilos.

Cuando llamas a Thread.Sleep, no importa cuán pequeño mates, todo el lapso de tiempo que Windows le dio al hilo, ya que no hay razón para esperarlo y el contexto cambia inmediatamente. Pueden pasar algunos ms cuando Windows le da a su hilo algo de CPU la próxima vez.

Qué usar?
Alternativamente, puede hacer girar su CPU , girar no es algo terrible de hacer y puede ser muy útil. Se usa, por ejemplo, en System.Collections.Concurrent namespace mucho con colecciones no bloqueantes, por ejemplo:

 SpinWait sw = new SpinWait(); sw.SpinOnce(); 

La mayoría de las razones legítimas para usar Thread.Sleep(1) o Thread.Sleep(0) implican técnicas de sincronización de hilos bastante avanzadas. Como dijo Reed , no obtendrás la resolución deseada usando técnicas convencionales. No sé con certeza qué es lo que estás tratando de lograr, pero creo que puedo suponer que quieres que ocurra una acción a intervalos de 1 milisegundo. Si ese es el caso, eche un vistazo a los temporizadores multimedia . Pueden proporcionar una resolución de hasta 1 ms. Desafortunadamente, no hay una API integrada en el .NET Framework (que yo sepa) que explota esta característica de Windows. Pero puede usar la capa de interoperabilidad para llamar directamente a las API de Win32. Incluso hay ejemplos de hacer esto en C # por ahí.

En los viejos tiempos, se usaba la API “QueryPerformanceTimer” de Win32, cuando se necesitaba una resolución inferior a milisegundos.

Parece que hay más información sobre el tema en Code-Project: http://www.codeproject.com/KB/cs/highperformancetimercshar.aspx

Esto no le permitirá “Dormir ()” con la misma resolución indicada por Reed Copsey.

Editar: Como señalan Reed Copsey y Brian Gideon, el QueryPerfomanceTimer ha sido reemplazado por Stopwatch en .NET