在C#中等待特定时间(比如10秒)的最佳方法是什么?

8

我希望等待15秒钟,然后控制应该从下一条语句继续执行。

在等待期间我没有其他事情要做(只是等待)。

我知道有Thread.Sleep(15000)。但我不知道最好的等待方法是什么?这种方法有哪些限制?

代码将会像这样:

Method()
{
   statement 1;
   statement 2;
   //WaitFor 15 secs here;
   statement 3;
}

Thread.Sleep(15000) 对于 C# 来说还好,但对于 WinForms、WPF 或 ASP.NET 来说就是一场灾难。 - H H
近似重复问题:https://dev59.com/JHNA5IYBdhLWcg3wGJ0V,http://stackoverflow.com/questions/407130,http://stackoverflow.com/questions/1208103和https://dev59.com/_0fRa4cB1Zd3GeqP_baI。 - Peter Mortensen
8个回答

13

Thread.Sleep的缺点是,如果在GUI线程(处理GUI事件的线程,例如按钮单击处理程序方法或从按钮单击处理程序调用的方法等)中调用它,则您的应用程序将在这15秒内似乎被冻结并且无响应。

如果您明确创建了一个单独的线程并在其中调用Thread.Sleep,假设您不介意该线程在15秒内不执行任何操作,那么这将是完全可以接受的。

另一种选择是在stmt 2之后创建一个计时器,并在计时器的Tick事件处理程序中放置stmt 3,同时在该处理程序中停止计时器。


7

这可能不是你问题的直接答案。我建议检查你的流程是否比检查代码更好;-)

你是在等待15秒钟来确保stmt2完成吗?如果是,那么在stmt2执行后立即添加一个处理程序可能是一个更好的解决方案(?)

你也可以使用计时器进行等待。 Thread.sleep 是一个糟糕的设计。我们有一个类似的问题,谈论了 使用 Thread.sleep 和 Timer 进行比较


3

试试以下类似的方法:

void Method()
{
    console.log('statement 1');
    console.log('statement 2');

    var timer = new System.Threading.Timer(
        o =>   // timer callback
        {
           console.log('statement 2');
        },
        15000, // Delay
        0      // Repeat-interval; 0 for no repeat
    );
}

该语法使用 C# 3.0,利用 lambda 表达式有效地创建了一个围绕第三条语句的闭包。这样,您可以使用 Method 的任何局部变量。需要注意的是,使用此方法或任何其他基于计时器的方法...函数将在创建计时器后立即返回。函数不会阻塞,直到计时器执行。要实现这一点,我能想到的唯一方法就是实际上使用线程,并使 Method() 在信号(即 WaitHandle、ResetEvent 等)上阻塞,直到在其他线程上定时调用完成。


5
这个例子存在问题。它不能可靠地工作,因为没有保留对“Timer”对象的引用。因此,它易受垃圾回收的影响。延迟越长,这个问题就越容易出现。根据MSDN文档:只要你在使用计时器,就必须保留对它的引用。和任何托管对象一样,当没有引用时,计时器也会被垃圾回收掉。即使计时器仍然处于活动状态,也不能防止它被回收。 - Thorarin
@Thorarin:啊,你说得对。我完全忘记了那个小事实。我会看看能否更正这个例子。 - jrista
如果您想在UI线程上分派回调,应改用System.Windows.Forms.Timer - Sam Harwell
stmt1无法编译。这是C#的关键字吗? - Exitos

3

如果在等待过程中没有其他事情需要处理,Thread.sleep似乎是一个明智的选择。它会将线程置于睡眠状态,以便在此期间不使用任何CPU资源。


是的,任何其他方法都会使用CPU,如果你只需要等待,那么你不想这样。 - awe
这在需要模拟时间差的单元测试中特别有用。在这种情况下,该方法不能退出,因此Thread.Sleep()的影响较小。对于长时间间隔,我通过更改系统时间来伪造它。有点像把计算机放入时间机器中。当测试完成后,它会将系统时间设置回正常状态。 - Gareth Farrington

2
void Method()
{
    Statement1();
    Statement2();

    // Start the timer for a single 15 second shot.
    // Keep a reference to it (Mytimer) so that the timer doesn't get collected as garbage
    Mytimer = new System.Threading.Timer((a) =>
        {
            // Invoke the 3rd statement on the GUI thread
            BeginInvoke(new Action(()=>{ Statement3(); }));
        }, 
    null,
    15000, // 15 seconds
    System.Threading.Timeout.Infinite); // No repeat
}

2

你可以使用计时器,在设定的时间后执行代码。但是,如果你不必要执行任何操作,只想在代码的特定点等待,那么我认为Thread.Sleep(150000);就足够了。


1
如果您想要在给定的时间内等待,那么Sleep是有用的。显然,在需要及时响应的线程上不应这样做。
请记住,在所有情况下,您的线程都会休眠相应的时间。如果出于某种原因您希望线程更快地恢复,最好使用信号或回调。通过使用这两者之一而不是Sleep,您将最小化不必要的等待时间。

-1

我不确定100%,但如果您确实需要在等待15秒后返回方法,请尝试以下操作:


Method()
{
   stmt1();
   stmt2();
int time = DateTime.Now.Millisecond; while (15*1000 > DateTime.Now.Millisecond - time) { Thread.Sleep(10) Application.DoEvents(); } stmt3(); }

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