web-dev-qa-db-fra.com

Temporisation dans la boucle For en c #

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.

11
Abdur Rahim

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.

  • Méthode 2: Simplement horrible: Dors le fil.

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 .

  • Méthode trois: divisez le travail en tâches plus petites. Créer une minuterie. Lorsque vous souhaitez un délai, créez une minuterie au lieu de la tâche suivante. Lorsque la minuterie déclenche son tick, ramassez la liste des tâches que vous avez laissées.

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.

  • Méthode 4: utilisez le support de C # 5 pour la programmation asynchrone; attend la tâche Delay et laisse le compilateur C # se charger de la restructuration de votre programme pour le rendre efficace.

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.

39
Eric Lippert

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
}
13
Adam Zalcman

Utilisez Thread.Sleep (de System.Threading):

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

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
2
niaher

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.

2
Servy

Essayez cette version plus simple sans dépendance sur async, wait ou TPL.

  1. Spawns 50 appels de méthode,
  2. dort pendant 20 secondes,
  3. vérifie si 20 ou x éléments sont complets.
  4. sinon dort encore pendant 20 secondes
  5. si oui reprend la boucle

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--;
)
0
Sundara Prabu