我想在两条指令之间等待几秒钟,但没有阻止执行。
例如,Thread.Sleep(2000)
它不好,因为它会阻止执行。
我的想法是我调用一个方法,然后等待X秒(例如20)监听一个事件。在20秒结束时,我应该根据20秒内发生的事情进行一些操作。
答案 0 :(得分:78)
我认为你所追求的是Task.Delay。这不像Sleep那样阻塞线程,这意味着你可以使用异步编程模型使用单个线程来完成这个。
async Task PutTaskDelay()
{
await Task.Delay(5000);
}
private async void btnTaskDelay_Click(object sender, EventArgs e)
{
await PutTaskDelay();
MessageBox.Show("I am back");
}
答案 1 :(得分:23)
我用:
private void WaitNSeconds(int segundos)
{
if (segundos < 1) return;
DateTime _desired = DateTime.Now.AddSeconds(segundos);
while (DateTime.Now < _desired) {
System.Windows.Forms.Application.DoEvents();
}
}
答案 2 :(得分:11)
这是使用另一个线程的好例子:
// Call some method
this.Method();
Task.Factory.StartNew(() =>
{
Thread.Sleep(20000);
// Do things here.
// NOTE: You may need to invoke this to your main thread depending on what you're doing
});
上面的代码需要.NET 4.0或更高版本,否则请尝试:
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
{
Thread.Sleep(20000);
// Do things here
}));
答案 3 :(得分:10)
如果您无法将环境升级到.NET 4.5以获得对异步和等待API的访问权限,那么Omar的解决方案就不错了。也就是说,为了避免表现不佳,应该进行一项重要的改变。在调用Application.DoEvents()之间应该稍加延迟,以防止过多的CPU使用。添加
Thread.Sleep(1);
在调用Application.DoEvents()之前,您可以添加这样的延迟(1毫秒)并阻止应用程序使用它可用的所有cpu周期。
private void WaitNSeconds(int seconds)
{
if (seconds < 1) return;
DateTime _desired = DateTime.Now.AddSeconds(seconds);
while (DateTime.Now < _desired) {
Thread.Sleep(1);
System.Windows.Forms.Application.DoEvents();
}
}
*有关使用Application.DoEvents()的潜在缺陷的更详细讨论,请参阅https://blog.codinghorror.com/is-doevents-evil/。
答案 4 :(得分:3)
如果您不想阻止事物并且也不想使用多线程,这里有适合您的解决方案: https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx
UI线程未被阻止,计时器等待2秒后再做一些事情。
以下是来自上述链接的代码:
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program... ");
Console.ReadLine();
Console.WriteLine("Terminating the application...");
答案 5 :(得分:2)
我真的不赞成你使用Thread.Sleep(2000)
,因为有几个原因(有些原因被描述为here),但最重要的是因为它在调试/测试方面没用。
我建议使用C# Timer代替Thread.Sleep()
。定时器允许您经常执行方法(如果需要)并且更容易在测试中使用!有一个非常好的例子,说明如何在超链接后面使用计时器 - 只需将你的逻辑“2秒后发生的事情”直接放入Timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
方法。
答案 6 :(得分:0)
查看System.Threading.Timer
课程。我认为这就是你要找的东西。
code example on MSDN似乎表明此课程与您尝试的内容非常相似(在一定时间后检查状态)。
答案 7 :(得分:0)
嗨,这是我的建议
.......
var t = Task.Run(async () => await Task.Delay(TimeSpan.FromSeconds(Consts.FiveHundred)).ConfigureAwait(false));
//just to wait task is done
t.Wait();
请牢记“等待”,否则“延迟”运行不会影响应用程序
答案 8 :(得分:-1)
如果可能的话,首选方法应该是使用异步方式或第二个线程。
如果不可能或不希望这样做,则使用DoEvents()
的任何实现都是一个坏主意,因为它可能会导致问题Possible problems with DoEvents。这主要是关于带有Winforms的DoEvent,但是WPF中可能存在的陷阱是相同的。
然后可以使用带有所需睡眠时间的框架放在分派器上:
using System;
using System.Threading;
using System.Windows.Threading;
public static void NonBlockingSleep(int timeInMilliseconds)
{
DispatcherFrame df = new DispatcherFrame();
new Thread((ThreadStart)(() =>
{
Thread.Sleep(TimeSpan.FromMilliseconds(timeInMilliseconds));
df.Continue = false;
})).Start();
Dispatcher.PushFrame(df);
}
答案 9 :(得分:-1)
在我的情况下,我需要执行此操作,因为我已将一个方法传递给正在等待的线程,并且由于该方法在GUI线程上运行,并且线程代码有时称为该方法,因此导致了锁定。
Task<string> myTask = Task.Run(() => {
// Your code or method call
return "Maybe you want to return other datatype, then just change it.";
});
// Some other code maybe...
while (true)
{
myTask.Wait(10);
Application.DoEvents();
if (myTask.IsCompleted) break;
}