c#中For循环的时间延迟

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

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

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

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

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

    DateTime timeToStartUpAgain = whatever;

    while(DateTime.Now < timeToStartUpAgain) {}

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

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

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

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

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

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

  • 方法四:使用C#5支持异步编程; 等待Delay任务 ,让C#编译器负责重构您的程序,使其高效。

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

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

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

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

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

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

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

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

这是我提出的实现。 它是通用的,因此您可以轻松地将其重用于您的用例。 (它与@Servy建议的一致)

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

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

  1. Spawns 50方法调用,
  2. 睡20秒,
  3. 检查它20或x项是否完整。
  4. 如果不再睡20秒
  5. 如果是,恢复循环

代码在这里

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