等待一段时间不阻塞主线程
Posted
技术标签:
【中文标题】等待一段时间不阻塞主线程【英文标题】:Wait for a while without blocking main thread 【发布时间】:2012-01-19 17:50:10 【问题描述】:我希望我的方法等待大约 500 毫秒,然后检查某些标志是否已更改。如何在不阻塞我的应用程序的其余部分的情况下完成此操作?
【问题讨论】:
这个问题被严重低估了;我们需要知道“应用程序的其余部分”是什么——它是否运行在同一个线程、不同的线程、不同的机器上,什么?也就是说,到目前为止,几乎所有的答案都是危险的。使用 DoEvents 或 Thread.Sleep 是最糟糕的做法,表明设计糟糕的应用程序存在严重的重入错误的危险。 Tudor 的答案是最好的:使用计时器。 另外,考虑研究 C# 5 的异步 CTP 版本。我们添加了控制流,让您可以轻松延迟 500 毫秒并从中断处继续,而不会阻塞任何线程或启动新线程消息循环。 【参考方案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(或根本不设置)。
【讨论】:
稍微修正一下,Interval
property 的值以 毫秒 为单位,而不是秒 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
那样阻塞线程,而且代码比定时器少得多。
【讨论】:
这需要 .NET 4.5,但如果你必须使用 .NET 4.0,你可以使用类似 ***.com/a/17717159/5815327 的东西。【参考方案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();
【讨论】:
以上是关于等待一段时间不阻塞主线程的主要内容,如果未能解决你的问题,请参考以下文章