2012-03-30 19 views
11

¿cómo puedo usar un retraso en un ciclo después de cierta rotación? Supongamos:Retraso en el ciclo For en C#

for(int i = 0 ; i<64;i++) 
{ 
........ 
} 

i quieren 1 retraso seg después de cada 8 rotación.

Respuesta

35

Hay muchas maneras de hacerlo:

  • Método uno: Criminalmente horrible Ocupado-espera:

    DateTime timeToStartUpAgain = whatever;

    while(DateTime.Now < timeToStartUpAgain) {}

Esto es una cosa horrible de hacer; el sistema operativo asumirá que está haciendo un trabajo útil y asignará una CPU para hacer nada más que girar sobre esto. Nunca haga esto a menos que sepa que el giro será de solo unos microsegundos. Básicamente, cuando haces esto, contrataste a alguien para que vigilara el reloj; eso no es económico

  • Método dos: Merely horrible: Duerme el hilo.

Dormir un hilo también es algo horrible de hacer, pero menos horrible que calentar una CPU. Dormir un hilo le dice al sistema operativo "este hilo de esta aplicación debe dejar de responder a los eventos por un tiempo y no hacer nada". Esto es mejor que contratar a alguien para mirar un reloj para ti; ahora que ha contratado a alguien para dormir para usted.

  • Método tres: Divida el trabajo en tareas más pequeñas. Crea un temporizador. Cuando desee un retraso, en lugar de hacer la siguiente tarea, haga un temporizador. Cuando el temporizador activa su evento tick, selecciona la lista de tareas donde lo dejaste.

Esto hace un uso eficiente de los recursos; ahora está contratando a alguien para cocinar huevos y mientras los huevos se cocinan, pueden hacer tostadas.

Sin embargo, es un dolor escribir su programa para que divida el trabajo en pequeñas tareas.

  • Método cuatro: use el soporte de C# 5 para programación asíncrona; espere la tarea Delay y deje que el compilador de C# se encargue de reestructurar su programa para que sea eficiente.

El inconveniente es que C# 5 solo está en beta en este momento.

NOTA: A partir de Visual Studio 2012 C# 5 está en uso. Si está utilizando VS 2012 o posterior, la programación asincrónica está disponible para usted.

7

Uso Thread.Sleep (de System.Threading):

for(int i = 0 ; i<64;i++) 
{ 
    if(i % 8 == 0) 
     Thread.Sleep(1000); 
} 
+0

+1 a ambas respuestas, también bloqueará el hilo de UI si se usa incorrectamente. –

+2

Eso dormirá después de la primera iteración. – user7116

12

Si quieres un sueño después de cada 8 iteraciones, intente esto:

for (int i = 0; i < 64; i++) 
{ 
    //... 
    if (i % 8 == 7) 
     Thread.Sleep(1000); //ms 
} 
2

También puede simplemente mirar en el uso de una Timer en lugar de pausar el hilo actual en un bucle.

Le permitirá ejecutar algún bloque de código (repetidamente o no) después de un intervalo de tiempo. Sin más contexto, sería difícil decir con certeza si es lo mejor en su situación o cómo podría modificar su solución en consecuencia.

1

Aquí está la implementación que se me ocurrió. Es genérico, por lo que puede reutilizarlo fácilmente para su caso de uso. (Se alinea con lo que sugirió @Servy)

public static async Task ForEachWithDelay<T>(this ICollection<T> items, Func<T, Task> action, double interval) 
{ 
    using (var timer = new System.Timers.Timer(interval)) 
    { 
     var task = new Task(() => { }); 
     int remaining = items.Count; 
     var queue = new ConcurrentQueue<T>(items); 

     timer.Elapsed += async (sender, args) => 
     { 
      T item; 
      if (queue.TryDequeue(out item)) 
      { 
       try 
       { 
        await action(item); 
       } 
       finally 
       { 
        // Complete task. 
        remaining -= 1; 

        if (remaining == 0) 
        { 
         // No more items to process. Complete task. 
         task.Start(); 
        } 
       } 
      } 
     }; 

     timer.Start(); 

     await task; 
    } 
} 

y luego usarlo como tal:

var numbers = Enumerable.Range(1, 10).ToList(); 
var interval = 1000; // 1000 ms delay 
numbers.ForEachWithDelay(i => Task.Run(() => Console.WriteLine(i + " @ " + DateTime.Now)), interval); 

que imprime esto:

1 @ 2/2/2016 9:45:37 AM 
2 @ 2/2/2016 9:45:38 AM 
3 @ 2/2/2016 9:45:39 AM 
4 @ 2/2/2016 9:45:40 AM 
5 @ 2/2/2016 9:45:41 AM 
6 @ 2/2/2016 9:45:42 AM 
7 @ 2/2/2016 9:45:43 AM 
8 @ 2/2/2016 9:45:44 AM 
9 @ 2/2/2016 9:45:45 AM 
10 @ 2/2/2016 9:45:46 AM 
0

probar este versión más sencilla y sin dependencia de asíncrono o espera o TPL.

  1. genera 50 llamadas de método,
  2. duerme durante 20 segundos,
  3. cheques TI 20 o x artículos se han completado.
  4. si no se duerme de nuevo durante 20 segundos
  5. en caso afirmativo se reanuda bucle Código

aquí

foreach (var item in collection) 
      { 
       if (cnt < 50) 
       { 
        cnt++; 
        DoWork(item); 
       } 
       else 
       { 
        bool stayinLoop = true; 
        while (stayinLoop) 
        { 
         Thread.Sleep(20000); 
         if (cnt < 30) 
         { 
          stayinLoop = false; 
          DoWork(item); 
         } 
        } 
       } 
      } 

hacer el trabajo en un hilo separado, por lo que el sueño no le bloquean, podría ser un trabajador en segundo plano, método Begin, End de webrequest u opcionalmente una tarea asíncrona o Task.Run()

function DoWork() 
//Do work in a sep thread. 
cnt--; 
) 
Cuestiones relacionadas