【问题标题】:Pausing a method for set # of milliseconds暂停设置 # of 毫秒的方法
【发布时间】:2010-11-07 06:44:13
【问题描述】:

我需要在我的方法中执行某种“超时”或暂停 10 秒(10000 毫秒),但我不确定以下是否可行,因为我没有多线程。

Thread.Sleep(10000);

我会尝试使用当前的代码,但如果有人能解释这样做的最佳和正确的方法,我将不胜感激,尤其是在上述代码无法正常工作的情况下。谢谢!

更新:这个程序实际上是一个控制台应用程序,它在所讨论的函数中对一个服务器执行许多 HTTPWebRequest,所以我希望将它们延迟指定的毫秒数。因此,不需要回调 - 所需要的只是“无条件暂停” - 基本上只是整个事情停止 10 秒然后继续。我很高兴 C# 仍然将其视为一个线程,因此 Thread.Sleep(...) 可以工作。谢谢大家!

【问题讨论】:

  • 我更新了帖子以阐明应用程序的性质。

标签: c# multithreading timeout


【解决方案1】:

您可能没有多线程,但您仍在一个线程中执行:所有代码都在一个线程中执行。

调用Thread.Sleep 确实会暂停当前线程。您真的希望它无条件地暂停 10 秒,还是希望能够被其他发生的事情“唤醒”?如果您实际上只使用一个线程,那么调用Sleep 可能是最好的方法,但这取决于具体情况。

特别是,如果您正在编写一个 GUI 应用程序,您希望在 UI 线程中使用 Thread.Sleep,否则您的整个应用程序将在 10 秒内无响应。 p>

如果您能提供有关您的申请的更多信息,这将有助于我们为您提供更好的建议。

【讨论】:

  • 我的应用程序实际上是一个控制台应用程序,它正在向一个服务器发出大量 HTTP 请求,所以我不想压倒它并在 4 个左右的批次之间暂停,这样已经自动暂停了,但是没有这样的代码。是的,我希望 C# 仍然将其识别为线程,所以谢谢!
【解决方案2】:

Thread.Sleep 很好,AFAIK 是正确的方法。即使您不是多线程:总是至少有一个线程,如果您将其发送到睡眠状态,它也会进入睡眠状态。

另一种(糟糕)方式is a spinlock,类似于:

// Do never ever use this
private void DoNothing(){ }

private void KillCPU()
{
    DateTime target = DateTime.Now.AddSeconds(10);
    while(DateTime.Now < target) DoNothing();
    DoStuffAfterWaiting10Seconds();
}

遗憾的是,这仍然被人们使用,虽然它会暂停你的程序 10 秒,但它会以 100% 的 CPU 利用率运行(嗯,在多核系统上它是一个核心)。

【讨论】:

  • 我对那个占用 CPU 的例子很感兴趣 - 需要把它写在我的书中,作为填满某人 CPU 的经典方式! :D 感谢您的提示!
  • while(DateTime.Now &lt; target) { } 也可以解决问题:)
  • 谢天谢地,我只是在线程和所有这些好东西方面很笨-{}我明白。 :D
  • 别笑-人们仍然使用它:/(好吧,在某些情况下自旋锁是合适的,但这就像所有情况的 0.0001%)。是的,我不确定“空”循环的规则,所以我添加了一个虚拟函数以确保 :)
【解决方案3】:

这确实会暂停正在执行的线程/方法 10 秒。您是否发现了具体问题?

请注意,您不应该 Sleep UI 线程 - 最好改为执行回调。

另请注意,还有其他阻塞线程的方法,允许更简单的访问以使其再次运行(如果您发现 2 秒后就可以了);比如Monitor.Wait(obj, 10000)(如果需要,允许另一个线程去Pulse唤醒它):

static void Main() {
    object lockObj = new object();
    lock (lockObj) {
        new Thread(GetInput).Start(lockObj);
        Monitor.Wait(lockObj, 10000);
    }
    Console.WriteLine("Main exiting");
}
static void GetInput(object state) {
    Console.WriteLine("press return...");
    string s = Console.ReadLine();
    lock (state) {
        Monitor.Pulse(state);
    }
    Console.WriteLine("GetInput exiting");
}

您也可以使用 Thread.Interrupt 来执行此操作,但 IMO 更麻烦。

【讨论】:

    【解决方案4】:

    您可以使用单独的线程来执行此操作:

       ThreadPool.QueueUserWorkItem(
           delegate(object state)
           {
               Thread.Sleep(1000);
               Console.WriteLine("done");
           });
    

    但是,如果这是一个 Windows 窗体应用程序,则需要在延迟后从 Gui 线程调用代码(本文,例如:How to update the GUI from another thread in C#?)。

    [编辑] 刚刚看到您的更新。如果它是控制台应用程序,那么这将起作用。但是如果你到目前为止还没有使用多线程,那么你需要注意这段代码将在不同的线程中执行,这意味着你必须注意线程同步问题。

    如果您不需要后台工作人员,请坚持“保持简单”。

    【讨论】:

      【解决方案5】:

      这是一个暂停类,它将暂停所需的毫秒数,并且不会消耗您的 CPU 资源。

      public class PauseClass
      {
          //(C) Michael Roberg
          //Please feel free to distribute this class but include my credentials.
      
          System.Timers.Timer pauseTimer = null;
      
          public void BreakPause()
          {
              if (pauseTimer != null)
              {
                  pauseTimer.Stop();
                  pauseTimer.Enabled = false;
              }    
          }
      
          public bool Pause(int miliseconds)
          {
              ThreadPriority CurrentPriority = Thread.CurrentThread.Priority;
      
              if (miliseconds > 0)
              {
                  Thread.CurrentThread.Priority = ThreadPriority.Lowest;
      
                  pauseTimer = new System.Timers.Timer();
                  pauseTimer.Elapsed += new ElapsedEventHandler(pauseTimer_Elapsed);
      
                  pauseTimer.Interval = miliseconds;
                  pauseTimer.Enabled = true;
      
                  while (pauseTimer.Enabled)
                  {
                      Thread.Sleep(10);
                      Application.DoEvents();
                      //pausThread.Sleep(1);
                  }
      
                  pauseTimer.Elapsed -= new ElapsedEventHandler(pauseTimer_Elapsed);
              }
      
              Thread.CurrentThread.Priority = CurrentPriority;
      
              return true;
          }
      
          private void pauseTimer_Elapsed(object sender, ElapsedEventArgs e)
          {
              pauseTimer.Enabled = false;
          }
      }
      

      【讨论】:

      • 使用示例
      • var p = new PauseClass(); p.暂停(1000); // 暂停 1 秒
      【解决方案6】:

      是的,效果很好。

      您不必拥有多个线程即可使用 Thread 类中的某些方法。你总是至少有一个线程。

      【讨论】:

        【解决方案7】:

        对于超时,您应该有一个静态的 volatile boolean isRunning 类字段。新线程启动时,isRunning 必须为 true,最后必须为 false。

        主线程应该有一个方法在你定义的超时期间为 isRunning 循环。当超时结束时,您应该实现逻辑。但是,永远不要使用中止线程方法。

        暂停...没有一个简单的解决方案。这取决于你在线程内做什么。不过,你可以看看Monitor.Wait

        【讨论】:

          【解决方案8】:

          如果你有一个异步方法,你可以做一些事情,比如在某个位置暂停函数。一旦 pause 设置为 false,它将继续执行方法中的其余代码。由于这是一个异步方法并且延迟也是异步的,因此 UI 执行不会受到影响。 * 请注意,asyn 仅在 .net 4.5 及更高版本中受支持。

          bool pause = true;
          
                 void async foo()
                  {
                  //some code
          
                      while (pause)
                       {
                       await Task.Delay(100);
                       }
          
                  //some code
                  }
          

          【讨论】: