如何在 C# 中重新启动任务?或如何重新启动 Thread.Sleep()?
Posted
技术标签:
【中文标题】如何在 C# 中重新启动任务?或如何重新启动 Thread.Sleep()?【英文标题】:How to restart a task in c#? or How to restart Thread.Sleep()? 【发布时间】:2021-08-27 12:27:46 【问题描述】:我一直在尝试制作一个 Windows 应用程序,当我收到一条消息“some_string”(来自服务器)时,我需要将标签的颜色(代码中的 sys2lbl)更改为绿色,并且它会保持绿色 15秒,然后变红。但是,例如,在第 5 秒内,如果我再次收到消息“some_string”,则标签应保持绿色多 15 秒,即总共 5+15 = 20。
我正在使用Task.Run(),根据我的理解,当我在这15秒内收到字符串'some_string'时,这个任务会以某种方式重新启动。
注意:如果我在 15 秒后收到“some_string”,此任务将完美运行。
有人知道怎么解决吗?
Task.Run(() =>
if (x.ApplicationMessage.Topic == "some_string")
sys2lbl.BackColor = Color.Green;
Thread.Sleep(15000);
sys2lbl.BackColor = Color.Red;
);
【问题讨论】:
我对@987654323@ 的理解是,它确实使您正在与之交互的线程处于休眠状态。在时间框架过去之前,您不能对该线程执行任何其他操作 - 这就是为什么 Thread.Sleep 在很多情况下不一定是一个好主意。看起来你可能想要Timer
类的一些行为:docs.microsoft.com/en-us/dotnet/api/…
在实践中当我收到来自服务器的消息时是什么意思?您是在轮询 API 还是服务器推送它?即,您是否有一种分派到 UI 线程的 Message Loop?还是事件驱动?异步? -- 如果需要启动后台线程来轮询服务器,则需要在 UI 线程中调用委托。那是您设置控件状态的地方(不是来自另一个线程/任务)。您可以在 UI 线程中使用 Timer,如果它仍然处于活动状态,则将其 Interval
增加 5 秒,否则只需启动它。 -- 如果你真的需要一个不同的线程。
我制作的 UI 订阅了 MQTT 服务器中的主题。因此,消息以随机方式发布在服务器中。每当我订阅一个特定主题时,标签应该变成绿色并保持一段时间然后变成红色。
那么,您是否使用经纪人的发布功能订阅特定主题?然后,您应该通过事件接收新消息,该事件在 UI 线程以外的线程中引发。您可以使用在 UI 线程中创建的委托将新数据编组到 UI 线程。当接收到事件时,您可以使用IProgrsss<T>
委托或Invoke()
/ BeginInvoke()
您自己的委托(您需要测试同步版本是否比异步版本更可靠)。如上所述,委托要么启动计时器,要么增加其间隔。
顺便说一句,不要用不相关的cancellationtoken
或诸如此类(好像你是 建议 解决方案)标记你的问题,你为什么不标记它mqtt
和发布您用来接收发布者通知的代码?您的客户也是发布者吗?即,您可能需要解决一些竞争条件。
【参考方案1】:
您可以使用来自System.Windows.Forms
命名空间的Timer
。在您的表单中声明
private readonly Timer _timer = new Timer();
像这样初始化它
public Form1()
InitializeComponent();
_timer.Interval = 15000; // Milliseconds
_timer.Tick += Timer_Tick;
private void Timer_Tick(object sender, EventArgs e)
_timer.Stop();
sys2lbl.BackColor = Color.Red;
然后你可以用
启动或重启定时器private void RestartTimer()
_timer.Stop();
sys2lbl.BackColor = Color.Green;
_timer.Start();
我经常使用这种技术来延迟查询的执行。例如,假设我们有一个数据网格和一个用于过滤网格中数据的文本框。在文本框的TextChanged
事件中,我们以短暂的延迟(例如,200 毫秒)启动计时器。在Timer_Tick
中,我们停止计时器并重新查询数据。
优点是无需用户按 Enter 或单击按钮即可重新查询数据。但另一方面,每次按键后都不会重新查询数据,如果查询执行速度很慢,这可能会出现问题。
如果用户在计时器延迟结束之前键入下一个字符,计时器将重新启动。如果在输入过滤器时执行查询,因为用户输入速度较慢,则将累积下一次击键,然后在数据更新完成时将其全部插入文本框中。这样可以减少重新查询的次数,并使 UI 响应更快。
请注意,在 Windows 窗体中,事件是严格按顺序执行的。新事件永远不会中断在 UI 线程上运行的方法(可以是事件处理程序)。因此,计时器永远不会出现多线程问题。
【讨论】:
以上是关于如何在 C# 中重新启动任务?或如何重新启动 Thread.Sleep()?的主要内容,如果未能解决你的问题,请参考以下文章