如何让我的C#程序休眠50毫秒?

333

我该如何让我的C#程序休眠(暂停执行)50毫秒?


17
如果我是VB.Net团队的一员,我会在语言的下一个版本中将分号(;)作为注释字符添加进来... - Joel Coehoorn
8
我认为VB程序员足够聪明,能够找出相应的等效方法。 - BlueRaja - Danny Pflughoeft
10个回答

414
System.Threading.Thread.Sleep(50);

请记住,如果在主GUI线程中执行此操作,将阻止GUI更新(它会感觉“迟钝”)。

只需删除 ; 即可使其适用于VB.net。


在一个方法中调用 sleep 后,程序是否会在后台继续执行(而不是创建新线程)?另外,如果我在一个新线程中调用 sleep,主线程是否会继续工作? - Jay Nirgudkar
@JayNirgudkar 调用 Sleep 的线程将会停止执行,其他线程不受影响。 - Isak Savo
1
这并不保证准确。 - Akumaburn

174

不同的编程语言中,等待基本上有三种选择:

  1. 松散等待
    • 执行线程阻塞指定的时间(= 不消耗处理能力)
    • 阻塞/等待线程无法进行处理
    • 不太精确
  2. 紧密等待(也称为紧密循环)
    • 处理器在整个等待间隔中非常繁忙(事实上,它通常会消耗一个核心处理时间的100%)
    • 可以在等待时执行某些操作
    • 非常精确
  3. 前两者混合
    • 通常结合了第一种的处理效率和第二种的精度+能够执行其他操作的能力。

C#中的松散等待:

Thread.Sleep(numberOfMilliseconds);

然而,Windows线程调度程序会导致Sleep()的准确性约为15毫秒(因此,即使计划等待1毫秒,Sleep也可以轻松地等待20毫秒)。

2. - 在C#中进行紧密等待的方法是:

Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
    //some other processing to do possible
    if (stopwatch.ElapsedMilliseconds >= millisecondsToWait)
    {
        break;
    }
}

我们也可以使用DateTime.Now或其他时间测量的方法,但Stopwatch更快(如果在紧密循环中,这将显得非常明显)。

对于3. - 组合:

Stopwatch stopwatch = Stopwatch.StartNew();
while (true)
{
    //some other processing to do STILL POSSIBLE
    if (stopwatch.ElapsedMilliseconds >= millisecondsToWait)
    {
        break;
    }
    Thread.Sleep(1); //so processor can rest for a while
}

这段代码定期阻塞线程1毫秒(或更长,具体取决于操作系统的线程调度),因此处理器在阻塞期间不会繁忙,并且代码不会消耗处理器的所有能力。在阻塞之间仍然可以执行其他处理(例如:更新UI、处理事件或执行交互/通信任务)。


3
计时器 也可能会引起兴趣。 - JonnyRaa

56

在Windows中,您无法指定精确的睡眠时间。要实现这一点,您需要一个实时操作系统。您能做的最好的事情是指定最小睡眠时间。然后由调度程序在此之后唤醒您的线程。并且绝对不要在GUI线程上调用.Sleep()方法。


55

现在有了 async/await 特性,最好的让程序等待50毫秒的方法是使用 Task.Delay:

async void foo()
{
    // something
    await Task.Delay(50);
}

如果你的目标是.NET 4(使用Async CTP 3 for VS2010或Microsoft.Bcl.Async),那么你必须使用:

async void foo()
{
    // something
    await TaskEx.Delay(50);
}

这样做可以避免阻塞用户界面线程。


在循环中,如果有延迟,你能否使用response.flush吗? - Teoman shipahi
不,你不能这样做。我相信有一个FlushAsync版本。 - Toni Petrina
9
一种不需要使用async声明的替代方法是调用Task.Delay(50).Wait(); - stuartd
建议仅在极度谨慎的情况下使用Wait,因为在异步操作上阻塞时可能会出现死锁。 - Craig

32

使用此代码

using System.Threading;
// ...
Thread.Sleep(50);

14
Thread.Sleep(50);

线程将不会按照指定的时间被操作系统调度执行。该方法改变线程的状态以包括WaitSleepJoin。

该方法不执行标准的COM和SendMessage泵。如果您需要在具有STAThreadAttribute的线程上睡眠,但想执行标准的COM和SendMessage泵,请考虑使用指定超时间隔的Join方法的重载之一。

Thread.Join

8

为了阅读易懂:

using System.Threading;
Thread.Sleep(TimeSpan.FromMilliseconds(50));

1

从.NET Framework 4.5开始,您可以使用:

最初的回答:

using System.Threading.Tasks;

Task.Delay(50).Wait();   // wait 50ms

1
发布于6年前 - GSerg
阻塞异步操作可能会导致死锁,使用时要非常小心。 - Craig

0
在C#中,你可以使用Thread.Sleep方法或Task.Delay来让你的程序暂停指定的毫秒数。以下是如何实现的示例:
using System;
using System.Threading;

class Program
{
    static void Main()
    {
        // Sleep for 50 milliseconds
        Thread.Sleep(50);
    Console.WriteLine("Sleep for 50 milliseconds");
    }
}

使用Task.Delay(异步方法):
using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main()
    {
        // Sleep for 50 milliseconds asynchronously
        await Task.Delay(50);
        
        // pause for 50 milliseconds and then continue execution.
        Console.WriteLine("resumed after sleeping for 50 ms.");
    }
}

-2

两全其美:

using System.Runtime.InteropServices;

    [DllImport("winmm.dll", EntryPoint = "timeBeginPeriod", SetLastError = true)]
    private static extern uint TimeBeginPeriod(uint uMilliseconds);

    [DllImport("winmm.dll", EntryPoint = "timeEndPeriod", SetLastError = true)]
    private static extern uint TimeEndPeriod(uint uMilliseconds);
    /**
     * Extremely accurate sleep is needed here to maintain performance so system resolution time is increased
     */
    private void accurateSleep(int milliseconds)
    {
        //Increase timer resolution from 20 miliseconds to 1 milisecond
        TimeBeginPeriod(1);
        Stopwatch stopwatch = new Stopwatch();//Makes use of QueryPerformanceCounter WIN32 API
        stopwatch.Start();

        while (stopwatch.ElapsedMilliseconds < milliseconds)
        {
            //So we don't burn cpu cycles
            if ((milliseconds - stopwatch.ElapsedMilliseconds) > 20)
            {
                Thread.Sleep(5);
            }
            else
            {
                Thread.Sleep(1);
            }
        }

        stopwatch.Stop();
        //Set it back to normal.
        TimeEndPeriod(1);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接