如何在一定的旋转后在循环中使用时间延迟? 假设:
for(int i = 0 ; i<64;i++)
{
........
}
我想在每8次旋转后延迟1秒。
答案 0 :(得分:40)
有很多方法可以做到这一点:
方法一:犯罪可怕:忙碌等待:
DateTime timeToStartUpAgain = whatever;
while(DateTime.Now < timeToStartUpAgain) {}
这是一件可怕的事情;操作系统将假设您正在做有用的工作,并将指定一个CPU除了旋转之外什么都不做。除非你知道旋转只会持续几微秒,否则永远不要这样做。基本上当你这样做时,你雇了一个人为你看时钟;这不经济。
睡觉线程也是一件可怕的事情,但不如加热CPU那么可怕。睡眠线程告诉操作系统“此应用程序的此线程应暂时停止响应事件并且不执行任何操作”。这比聘请某人为你看钟表更好;现在你雇了一个人为你睡觉。
这有效地利用了资源;现在你正在雇人煮鸡蛋,而鸡蛋正在做饭,他们可以做吐司。
然而,编写程序以便将工作分解为小任务是一件痛苦的事。
这方面的缺点当然是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。
此处代码
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--;
)