c#中For循环的时间延迟

时间:2012-03-30 16:21:21

标签: c# timer

如何在一定的旋转后在循环中使用时间延迟? 假设:

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

我想在每8次旋转后延迟1秒。

7 个答案:

答案 0 :(得分:40)

有很多方法可以做到这一点:

  • 方法一:犯罪可怕:忙碌等待:

    DateTime timeToStartUpAgain = whatever;

    while(DateTime.Now < timeToStartUpAgain) {}

这是一件可怕的事情;操作系统将假设您正在做有用的工作,并将指定一个CPU除了旋转之外什么都不做。除非你知道旋转只会持续几微秒,否则永远不要这样做。基本上当你这样做时,你雇了一个人为你看时钟;这不经济。

  • 方法二:非常糟糕:睡觉了。

睡觉线程也是一件可怕的事情,但不如加热CPU那么可怕。睡眠线程告诉操作系统“此应用程序的此线程应暂时停止响应事件并且不执行任何操作”。这比聘请某人为你看钟表更好;现在你雇了一个人为你睡觉

  • 方法三:将工作分解为更小的任务。创建一个计时器。当你想要延迟时,不要做下一个任务,而是做一个计时器。当计时器触发其嘀嗒事件时,请选择您离开的任务列表。

这有效地利用了资源;现在你正在雇人煮鸡蛋,而鸡蛋正在做饭,他们可以做吐司。

然而,编写程序以便将工作分解为小任务是一件痛苦的事。

  • 方法四:使用C#5支持异步编程; 等待延迟任务,让C#编译器负责重构你的程序,使其更有效率。

这方面的缺点当然是C#5目前仅处于测试阶段。

注意:从Visual Studio 2012开始,C#5正在使用中。如果您使用的是VS 2012或更高版本,则可以使用异步编程。

答案 1 :(得分:14)

如果你想在每8次迭代后休眠一下,试试这个:

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

答案 2 :(得分:8)

使用Thread.Sleep(来自System.Threading):

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

答案 3 :(得分:2)

您可能还想查看使用Timer而不是暂停当前线程。

它允许您在一段时间后执行一些代码块(重复或不重复)。如果没有更多背景信息,很难确定在您的情况下这是否最好,或者您将如何相应地改变您的解决方案。

答案 4 :(得分:2)

这是我提出的实现。它是通用的,因此您可以轻松地将其重用于您的用例。 (它与@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

答案 5 :(得分:1)

一旦我需要编写一个程序,女巫是如此敏感并且需要准确的时间安排(约纳秒)。

我使用了诸如Thread.Sleep(),Timer之类的各种各样的东西,但是没有一个能满足我的需求,因此我用这段代码来延迟:

var stopWatch = new Stopwatch();
for(int i = 0 ; i<64;i++)
{
stopWatch.Restart();
while (stopWatch.ElapsedMilliseconds <= 1000)
{

}
}

当然,这种方式对CPU不太友好,但是当您需要准确性时,就必须花很多时间去上学。

答案 6 :(得分:0)

尝试这个更简单的版本,不依赖于异步或等待或TPL。

  1. Spawns 50方法调用,
  2. 睡20秒,
  3. 检查20或x项 完成了。
  4. 如果不再睡20秒
  5. 如果是,则恢复循环
  6. 此处代码

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

    在单独的线程中工作,以便睡眠不阻止你,可以是后台工作者,开始,结束webrequest方法或可选的异步任务或Task.Run()

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