Временная задержка в цикле for в С#

как я могу использовать временную задержку в цикле после определенного поворота? Пусть:

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

Мне нужно 1 с задержка после каждого 8 вращений.

Ответ 1

Существует много способов сделать это:

  • Первый метод: преступный ужас: ожидание:

    DateTime timeToStartUpAgain = whatever;

    while(DateTime.Now < timeToStartUpAgain) {}

Это ужасная вещь; операционная система предположит, что вы делаете полезную работу и назначаете процессор, чтобы ничего не делать, кроме как откручивать его. Никогда не делайте этого, если не знаете, что вращение будет только на несколько микросекунд. В основном, когда вы делаете это, вы наняли кого-нибудь, чтобы посмотреть часы для вас; что неэкономично.

  • Метод второй: Просто ужасный: спящий поток.

Спящий поток также ужасен, но он менее ужасен, чем нагрев процессора. Спящий поток сообщает операционной системе "этот поток этого приложения должен перестать отвечать на события на какое-то время и ничего не делать". Это лучше, чем нанять кого-то, чтобы посмотреть часы для вас; теперь вы наняли кого-то, чтобы спать для вас.

  • Третий способ: разбить работу на более мелкие задачи. Создайте таймер. Если вам нужна задержка, вместо выполнения следующей задачи сделайте таймер. Когда таймер запускает свое событие tick, выберите список задач, в которых вы остановились.

Это эффективно использует ресурсы; теперь вы нанимаете кого-то, чтобы готовить яйца, и пока яйца готовят, они могут делать тосты.

Однако больно писать вашу программу, чтобы она разбивала работу на небольшие задачи.

  • Метод четыре: используйте поддержку С# 5 для асинхронного программирования; ожидание задачи Delay и позволить компилятору С# позаботиться о реструктуризации вашей программы, чтобы сделать ее эффективной.

С другой стороны, С# 5 - это только бета-версия.

ПРИМЕЧАНИЕ. С Visual Studio 2012 С# 5 используется. Если вы используете VS 2012 или более позднее, для вас доступно асинхронное программирование.

Ответ 2

Если вы хотите спать после каждых 8 итераций, попробуйте следующее:

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

Ответ 3

Используйте Thread.Sleep (из System.Threading):

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

Ответ 4

Вы также можете просто посмотреть на использование Timer, а не на приостановку текущего потока в цикле.

Это позволит вам выполнить некоторый блок кода (многократно или не) после некоторого промежутка времени. Без лишнего контекста было бы трудно сказать, насколько это лучше в вашей ситуации или как вы собираетесь изменить свое решение соответственно.

Ответ 5

Вот реализация, с которой я столкнулся. Он общий, поэтому вы можете легко его повторно использовать для своего случая использования. (он согласуется с тем, что предложил @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;
    }
}

И затем используйте его так:

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

который печатает это:

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

Ответ 6

Попробуйте эту более простую версию без зависимости от async или ожидания или TPL.

  • Вызывает 50 вызовов методов,
  • спит в течение 20 секунд,
  • проверяет его на 20 или x элементов завершены.
  • если не спит снова в течение 20 секунд
  • если да возобновляет цикл

Код здесь

 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);
                        }
                    }
                }
            }

Работайте в отдельном потоке, чтобы сон не блокировал вас, мог быть фоновым работником, Begin, End методом webrequest или, возможно, асинхронной задачей или Task.Run()

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