C# 在不阻止UI执行的情况下等待几秒钟
我想在两条指令之间等待几秒钟,但不阻止执行 例如,C# 在不阻止UI执行的情况下等待几秒钟,c#,timer,wait,C#,Timer,Wait,我想在两条指令之间等待几秒钟,但不阻止执行 例如,Thread.Sleep(2000)它不好,因为它会阻止执行 我的想法是调用一个方法,然后等待X秒(例如20秒),等待事件的到来。在20秒结束时,我应该根据20秒内发生的情况执行一些操作。这是使用另一个线程的好例子: // Call some method this.Method(); Task.Factory.StartNew(() => { Thread.Sleep(20000); // Do things here
Thread.Sleep(2000)
它不好,因为它会阻止执行
我的想法是调用一个方法,然后等待X秒(例如20秒),等待事件的到来。在20秒结束时,我应该根据20秒内发生的情况执行一些操作。这是使用另一个线程的好例子:
// 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
}));
查看
System.Threading.Timer
类。我想这就是你要找的
似乎显示该类的操作与您尝试执行的操作非常相似(在特定时间后检查状态)
MSDN链接中提到的代码示例:
using System;
using System.Threading;
class TimerExample
{
static void Main()
{
// Create an AutoResetEvent to signal the timeout threshold in the
// timer callback has been reached.
var autoEvent = new AutoResetEvent(false);
var statusChecker = new StatusChecker(10);
// Create a timer that invokes CheckStatus after one second,
// and every 1/4 second thereafter.
Console.WriteLine("{0:h:mm:ss.fff} Creating timer.\n",
DateTime.Now);
var stateTimer = new Timer(statusChecker.CheckStatus,
autoEvent, 1000, 250);
// When autoEvent signals, change the period to every half second.
autoEvent.WaitOne();
stateTimer.Change(0, 500);
Console.WriteLine("\nChanging period to .5 seconds.\n");
// When autoEvent signals the second time, dispose of the timer.
autoEvent.WaitOne();
stateTimer.Dispose();
Console.WriteLine("\nDestroying timer.");
}
}
class StatusChecker
{
private int invokeCount;
private int maxCount;
public StatusChecker(int count)
{
invokeCount = 0;
maxCount = count;
}
// This method is called by the timer delegate.
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine("{0} Checking status {1,2}.",
DateTime.Now.ToString("h:mm:ss.fff"),
(++invokeCount).ToString());
if(invokeCount == maxCount)
{
// Reset the counter and signal the waiting thread.
invokeCount = 0;
autoEvent.Set();
}
}
}
// The example displays output like the following:
// 11:59:54.202 Creating timer.
//
// 11:59:55.217 Checking status 1.
// 11:59:55.466 Checking status 2.
// 11:59:55.716 Checking status 3.
// 11:59:55.968 Checking status 4.
// 11:59:56.218 Checking status 5.
// 11:59:56.470 Checking status 6.
// 11:59:56.722 Checking status 7.
// 11:59:56.972 Checking status 8.
// 11:59:57.223 Checking status 9.
// 11:59:57.473 Checking status 10.
//
// Changing period to .5 seconds.
//
// 11:59:57.474 Checking status 1.
// 11:59:57.976 Checking status 2.
// 11:59:58.476 Checking status 3.
// 11:59:58.977 Checking status 4.
// 11:59:59.477 Checking status 5.
// 11:59:59.977 Checking status 6.
// 12:00:00.478 Checking status 7.
// 12:00:00.980 Checking status 8.
// 12:00:01.481 Checking status 9.
// 12:00:01.981 Checking status 10.
//
// Destroying timer.
我想你想要的是任务。延迟。这不会像Sleep那样阻塞线程,这意味着您可以使用异步编程模型使用单个线程来实现这一点
async Task PutTaskDelay()
{
await Task.Delay(5000);
}
private async void btnTaskDelay_Click(object sender, EventArgs e)
{
await PutTaskDelay();
MessageBox.Show("I am back");
}
我真的不建议您使用
Thread.Sleep(2000)
,因为有几个原因(描述了几个),但最重要的是,它在调试/测试时没有用处
我建议使用而不是
Thread.Sleep()
。计时器可以让您频繁地执行方法(如果必要的话),并且在测试中使用起来更容易!有一个很好的例子说明了如何在超链接后面使用计时器-只需将您的逻辑“2秒后发生的事情”直接放入timer.appeased+=new-ElapsedEventHandler(OnTimedEvent)代码>方法。如果您不想阻塞内容,也不想使用多线程,以下是您的解决方案:
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...");
我使用:
private void WaitNSeconds(int segudos)
{
如果(segudos<1)返回;
DateTime _desired=DateTime.Now.AddSeconds(segudos);
while(DateTime.Now<\u所需){
System.Windows.Forms.Application.DoEvents();
}
}
如果您无法将环境升级到.NET 4.5以访问异步API和等待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();
}
}
private void WaitNSeconds(整数秒)
{
如果(秒<1)返回;
DateTime _desired=DateTime.Now.AddSeconds(秒);
while(DateTime.Now<\u所需){
睡眠(1);
System.Windows.Forms.Application.DoEvents();
}
}
*有关使用Application.DoEvents()的潜在陷阱的更详细讨论,请参阅。如果可能,首选方法应使用异步方式或第二个线程
如果这不可能或不需要,那么使用DoEvents()
的任何实现都是一个坏主意,因为它可能会导致问题。这主要是关于Winforms中的DoEvents,但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);
}
嗨,这是我的建议
.......
var t = Task.Run(async () => await Task.Delay(TimeSpan.FromSeconds(Consts.FiveHundred)).ConfigureAwait(false));
//just to wait task is done
t.Wait();
请记住使用“wait”,否则延迟运行时不会影响应用程序。在我的情况下,我需要这样做,因为我已将一个方法传递给等待的线程,这导致了锁定,因为metod是在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;
}
Task myTask=Task.Run(()=>{
//您的代码或方法调用
return“可能您想返回其他数据类型,然后只需更改它。”;
});
//可能还有其他代码。。。
while(true)
{
myTask.Wait(10);
Application.DoEvents();
如果(myTask.IsCompleted)中断;
}
我们能看看你的意思吗?这是非常广泛的。此外,您正在构建一种应用程序吗?控制台、WPF、Winforms、ASP.NET应用程序或其他东西?您是否总是希望等待事件发生X秒,或者如果事件发生,您是否可以在事件发生时立即执行某些操作,如果事件未在X秒内发生,则执行其他操作,例如,像超时?你能提供一个小样本吗?@Jeroenvanevel在我帖子的链接中有一个例子。我还缺少什么补充?@Jeroenvanevel您应该添加一个示例,这样即使链接无效,您的答案仍能提供一个值。另外,“查看foobar”本身的价值很小。我不会将这个答案标记为“非答案”,但一些用户已经这样做了。谢谢,它看起来很有趣。我只有一个问题,C#无法识别async和Wait。你知道为什么吗?它们是对.Net Framework的全新添加,是在Visual Studio 2012和2013上与4.5版一起添加的。如果有帮助的话,这里有一个nuget软件包。谢谢。我安装了Visual Studio Express 2013,它现在有async和Wait。但是当想要使用任务延迟的方法时,它是不存在的。唯一允许的方法是Equals、ReferenceEquals、WaitAll和WaitAny。。。你知道为什么吗?你甚至不需要PutTaskDelay()
只要调用wait Task.Delay(5000)代码>directly@Black这是你的改进版。这一点是正确的。如果你想办法改进解决方案,可以发表评论让作者决定做出改变,也可以发表你的备选方案作为你自己的答案(酌情引用衍生作品)。将您的新版本编辑到其他人的答案中是不合适的。我只想在我自己的旧答案中添加一条注释,说明我更喜欢其他答案中提到的异步方法,因为它们更干净,实践效果更好。如果你没有艾尔
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;
}