如何在 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;
    
);

【问题讨论】:

我对@9​​87654323@ 的理解是,它确实使您正在与之交互的线程处于休眠状态。在时间框架过去之前,您不能对该线程执行任何其他操作 - 这就是为什么 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()?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不杀死未完成的芹菜任务的情况下重新启动heroku应用程序

如何使用任务计划程序重新启动 Windows 服务

即使设备在本机反应中重新启动,如何运行后台任务?

如何在 C# .NET 中检测应用程序池重新启动?

如何在 Airflow 上重新启动失败的任务

如何使用 PowerShell 在系统重新启动后延迟 10 分钟在 Windows 任务计划程序中安排任务?