C#中For循环中的时间延迟

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9946782/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 11:20:06  来源:igfitidea点击:

Time delay in For loop in c#

c#timer

提问by Abdur Rahim

how can i use a time delay in a loop after certain rotation? Suppose:

在特定旋转后如何在循环中使用时间延迟?认为:

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

i want 1 sec delay after each 8 rotation.

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

采纳答案by Eric Lippert

There are a lot of ways to do that:

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

  • Method one: Criminally awful: Busy-wait:

    DateTime timeToStartUpAgain = whatever;

    while(DateTime.Now < timeToStartUpAgain) {}

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

    DateTime timeToStartUpAgain = whatever;

    while(DateTime.Now < timeToStartUpAgain) {}

This is a horrible thing to do; the operating system will assume that you are doing useful work and will assign a CPU to do nothing other than spinning on this. Never do this unless you know that the spin will be only for a few microseconds. Basically when you do this you've hired someone to watch the clock for you; that's not economical.

这是一件可怕的事情;操作系统会假设你在做有用的工作,并且会分配一个 CPU 来做除了旋转之外的其他事情。除非您知道自旋只会持续几微秒,否则切勿这样做。基本上,当你这样做时,你已经雇了一个人为你看钟;那不经济。

  • Method two: Merely awful: Sleep the thread.
  • 方法二: 非常糟糕:休眠线程。

Sleeping a thread is also a horrible thing to do, but less horrible than heating up a CPU. Sleeping a thread tells the operating system "this thread of this application should stop responding to events for a while and do nothing". This is better than hiring someone to watch a clock for you; now you've hired someone to sleep for you.

休眠线程也是一件可怕的事情,但不如加热 CPU 可怕。休眠一个线程告诉操作系统“这个应用程序的这个线程应该停止响应事件一段时间并且什么都不做”。这比雇人为你看钟要好;现在你已经雇了人帮你睡觉了

  • Method three: Break up the work into smaller tasks. Create a timer. When you want a delay, instead of doing the next task, make a timer. When the timer fires its tick event, pick up the list of tasks where you left off.
  • 方法三:把工作分解成更小的任务。创建一个计时器。当你想要延迟时,与其做下一个任务,不如做一个计时器。当计时器触发其滴答事件时,从您停止的地方选择任务列表。

This makes efficient use of resources; now you are hiring someone to cook eggs and while the eggs are cooking, they can be making toast.

这样可以有效地利用资源;现在你要雇人煮鸡蛋,当鸡蛋在煮的时候,他们可以做吐司。

However it is a pain to write your program so that it breaks up work into small tasks.

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

  • Method four: use C# 5's support for asynchronous programming; await the Delay taskand let the C# compiler take care of restructuring your program to make it efficient.
  • 方法四:使用C#5对异步编程的支持;等待延迟任务,让 C# 编译器负责重组您的程序以使其高效。

The down side of that is of course C# 5 is only in beta right now.

不利的一面当然是 C# 5 目前仅处于测试阶段。

NOTE: As of Visual Studio 2012 C# 5 is in use. If you are using VS 2012 or later async programming is available to you.

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

回答by alexn

Use Thread.Sleep(from System.Threading):

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

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

回答by Adam Zalcman

If you want a sleep after each 8 iterations, try this:

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

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

回答by Servy

You may also want to just look into using a Timerrather than pausing the current thread in a loop.

您可能还想考虑使用 aTimer而不是在循环中暂停当前线程。

It will allow you to execute some block of code (repeatedly or not) after an interval of time. Without more context it would be hard to say for sure if that's best in your situation or how you would go about altering your solution accordingly.

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

回答by niaher

Here is the implementation I came up with. It's generic, so you can easily reuse it for your use case. (it aligns with what @Servy suggested)

这是我想出的实现。它是通用的,因此您可以轻松地在您的用例中重用它。(它与@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;
    }
}

And then use it as so:

然后这样使用它:

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

which prints this:

打印这个:

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

回答by Sundara Prabu

Try this simpler version without dependency on async or await or TPL.

试试这个更简单的版本,而不依赖于 async 或 await 或 TPL。

  1. Spawns 50 method calls ,
  2. sleeps for 20 secs,
  3. checks it 20 or x items are complete.
  4. if not sleeps again for 20 secs
  5. if yes resumes loop
  1. 产生 50 个方法调用,
  2. 睡20秒,
  3. 检查 20 或 x 项是否完整。
  4. 如果没有再睡 20 秒
  5. 如果是,则恢复循环

Code here

代码在这里

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

Do work in a separate thread, so that sleep doesn't block you, could be a background worker , Begin , End method of webrequest or optionally an async task or Task.Run()

在一个单独的线程中工作,这样 sleep 就不会阻止你,可以是后台工作人员,开始,结束 webrequest 方法或可选的异步任务或 Task.Run()

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