【问题标题】:Wait for a while without blocking main thread等待一段时间不阻塞主线程
【发布时间】:2012-01-19 17:50:10
【问题描述】:

我希望我的方法等待大约 500 毫秒,然后检查某些标志是否已更改。如何在不阻塞我的应用程序的其余部分的情况下完成此操作?

【问题讨论】:

  • 这个问题被严重低估了;我们需要知道“应用程序的其余部分”是什么——它是否运行在同一个线程、不同的线程、不同的机器上,什么?也就是说,到目前为止,几乎所有的答案都是危险的。使用 DoEvents 或 Thread.Sleep 是最糟糕的做法,表明设计糟糕的应用程序存在严重的重入错误的危险。 Tudor 的答案是最好的:使用计时器。
  • 另外,考虑研究 C# 5 的异步 CTP 版本。我们添加了控制流,让您可以轻松延迟 500 毫秒并从中断处继续,而不会阻塞任何线程或启动新线程消息循环。

标签: c# multithreading wait


【解决方案1】:

如果有问题的方法在与应用程序的其余部分不同的线程上执行,则执行以下操作:

Thread.Sleep(500);

【讨论】:

  • @user898569 根据定义,如果您想“等待某事”,则需要坐在那里“等待”。所以不,你必须使用另一个线程,否则它会阻塞你的程序。请参阅Tudor's answer 了解触发将在主线程上运行但不会“等待”的事件的方法,它只是一个周期性事件。
  • 有趣的问题。我建议您阅读 .NET 中的异步编程。这是一个良好起点的链接:msdn.microsoft.com/en-us/vstudio/gg316360
【解决方案2】:
System.Threading.Thread.Sleep(500);

更新

这不会阻塞应用程序的其余部分,只会阻塞运行方法的线程。

【讨论】:

  • 大声笑,我的输入时间超过 7 秒,因为我放入了命名空间。不是第一个:(
【解决方案3】:

我不太明白这个问题。

如果你想在检查之前阻止,请使用Thread.Sleep(500);

如果您想每 x 秒异步检查一次,您可以使用 Timer 每 x 毫秒执行一次处理程序。

这不会阻塞你当前的线程。

【讨论】:

  • 我认为这是 OP 需要的。
  • 如果它是一个 GUI 应用程序,那么最好使用特定于所用 GUI 库的计时器(例如,在 WPF 的情况下为DispatcherTimer)。
  • “每 x 秒检查一次”和“等待 x 秒然后检查”是有区别的。我相信 OP 想要后者。
【解决方案4】:

Thread.Sleep(500) 将强制当前线程等待 500 毫秒。它可以工作,但如果您的整个应用程序在一个线程上运行,这不是您想要的。

在这种情况下,您需要使用Timer,如下所示:

using System.Timers;

void Main()
{
    Timer t = new Timer();
    t.Interval = 500; // In milliseconds
    t.AutoReset = false; // Stops it from repeating
    t.Elapsed += new ElapsedEventHandler(TimerElapsed);
    t.Start();
}

void TimerElapsed(object sender, ElapsedEventArgs e)
{
    Console.WriteLine("Hello, world!");
}

如果您希望计时器自动重复,您可以将 AutoReset 设置为 true(或根本不设置)。

【讨论】:

  • 稍微修正一下,Intervalproperty 的值以 毫秒 为单位,而不是秒 link
  • 当前线程非常有帮助。我错误地认为Thread.Sleep 导致主线程休眠。
  • 我认为您可以向后使用 AutoReset。将其设置为 true 或根本不设置它会使计时器重复自身。 link
  • @JochemKempe 已修复,但我不确定您为什么一年多前没有这样做。留下这条评论是为了避免让未来的 Google 员工感到困惑。
【解决方案5】:

使用计时器应该可以解决问题

如果您需要使用线程,那么这里是一个示例

void Main()
{
    System.Threading.Thread check= new System.Threading.Thread(CheckMethod);
    check.Start();
}

private void CheckMethod()
{
     //Code
     Thread.Sleep(500);
}

【讨论】:

    【解决方案6】:

    异步任务:

     var task = new Task (() => function_test()); task.Start();
    
    public void function_test() { `Wait for 5000 miliseconds`   Task.Delay(5000);` }
    

    【讨论】:

      【解决方案7】:

      您可以使用await Task.Delay(500); 而不会像Sleep 那样阻塞线程,而且代码比定时器少得多。

      【讨论】:

      【解决方案8】:

      我最近一直在努力解决同样的问题,即我需要在不阻塞 UI 的情况下按计划运行操作。

      这是我的解决方案:

      private void Button_Click(object sender, RoutedEventArgs e)
      {
          RunOnSchedule(interval, cancellationToken);
      }
      
      private void RunOnSchedule(int interval, CancellationToken cancellationToken)
      {
          // Start the task you want to run on schedule
          TaskToRunOnSchedule(args);
          Task.Run(async () => 
          {
              // This loop checks if the task was requested to be cancelled every 1000 ms
              for (int x = 0; x < interval; x+=1000)
              {
                  if (cancellationToken.IsCancellationRequested)
                  {
                      break;
                  }
      
                  await Task.Delay(1000);
              }
          }).GetAwaiter().OnCompleted(() =>
          {
              // Once the task for delaying is completed, check once more if cancellation is requested, as you will reach this point regardless of if it was cancelled or not.
              if (!cancellationToken.IsCancellationRequested)
              {
                  // Run this method again
                  RunOnSchedule(interval, cancellationToken);
              }
          });
      }
      

      【讨论】:

        【解决方案9】:

        在一个 WinForms 应用程序中,当我想在主线程上等待而不阻塞应用程序时,我通常使用

        private void Wait (double milliseconds)
        {
            DateTime next = System.DateTime.Now.AddMilliseconds(milliseconds);
            while (next > System.DateTime.Now)
                Application.DoEvents();
        }
        

        【讨论】:

          猜你喜欢
          • 2011-11-20
          • 1970-01-01
          • 2021-12-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多