comment puis-je utiliser un délai dans une boucle après une certaine rotation? Supposer:
for(int i = 0 ; i<64;i++)
{
........
}
je veux 1 seconde de retard après chaque rotation 8.
Il y a beaucoup de façons de le faire:
Première méthode: Criminellement horrible: Occupé-attendre:
DateTime timeToStartUpAgain = whatever;
while(DateTime.Now < timeToStartUpAgain) {}
C'est une chose horrible à faire. le système d'exploitation supposera que vous effectuez un travail utile et affectera un processeur à cette tâche. Ne faites jamais ceci à moins que vous sachiez que le spin ne sera que pour quelques microsecondes . En gros, lorsque vous faites cela, vous avez engagé quelqu'un pour surveiller l'horloge à votre place; ce n'est pas économique.
Dormir un fil est également une chose horrible à faire, mais moins horrible que de chauffer un processeur. Mettre un thread en veille dit au système d'exploitation "ce thread de cette application doit cesser de répondre aux événements pendant un moment et ne rien faire". C'est mieux que d'engager quelqu'un pour regarder une horloge pour vous; maintenant vous avez engagé quelqu'un dormir pour vous .
Cela permet une utilisation efficace des ressources. Maintenant, vous embauchez quelqu'un pour faire cuire des œufs et pendant que les œufs cuisent, ils peuvent faire des toasts.
Cependant, il est difficile d’écrire votre programme de manière à ce qu’il se décompose en petites tâches.
L’inconvénient est que C # 5 n’est actuellement qu’en version bêta.
REMARQUE: à partir de Visual Studio 2012 C # 5 est en cours d'utilisation. Si vous utilisez VS 2012 ou une version ultérieure, la programmation asynchrone est disponible.
Si vous voulez dormir après chaque 8 itérations, essayez ceci:
for (int i = 0; i < 64; i++)
{
//...
if (i % 8 == 7)
Thread.Sleep(1000); //ms
}
Utilisez Thread.Sleep (de System.Threading):
for(int i = 0 ; i<64;i++)
{
if(i % 8 == 0)
Thread.Sleep(1000);
}
Voici la mise en œuvre que je suis venu avec. C'est générique, vous pouvez donc le réutiliser facilement pour votre cas d'utilisation. (cela correspond à ce que @Servy a suggéré)
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;
}
}
Et puis utilisez-le comme suit:
var numbers = Enumerable.Range(1, 10).ToList();
var interval = 1000; // 1000 ms delay
numbers.ForEachWithDelay(i => Task.Run(() => Console.WriteLine(i + " @ " + DateTime.Now)), interval);
qui imprime ceci:
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
Vous voudrez peut-être aussi simplement utiliser une Timer
plutôt que de suspendre le thread actuel dans une boucle.
Cela vous permettra d'exécuter un bloc de code (de manière répétée ou non) après un intervalle de temps. Sans plus de contexte, il serait difficile de dire avec certitude si cela convient le mieux à votre situation ou comment vous allez modifier votre solution en conséquence.
Essayez cette version plus simple sans dépendance sur async, wait ou TPL.
Code ici
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);
}
}
}
}
Travaillez dans un thread séparé, afin que la veille ne vous bloque pas, pourrait être un travailleur en arrière-plan, une méthode de webrequest Begin, End ou éventuellement une tâche asynchrone ou Task.Run ()
function DoWork()
//Do work in a sep thread.
cnt--;
)