如何在 C# 中每天激活一次线程

Posted

技术标签:

【中文标题】如何在 C# 中每天激活一次线程【英文标题】:How to have a thread activate once a day in C# 【发布时间】:2020-10-12 17:17:18 【问题描述】:

我有一个 WPF 应用程序,它的任务是导致旧订单过期。导致订单过期的线程需要每天运行一次。我目前有下面的代码来完成我想要完成的工作(对代码进行了一些简化)。

我的问题是我的方法是否有意义,或者是否有更好的方法来完成任务。

有没有办法让线程等到天变了?这会是一个好的解决方案吗?

我使用的线程类型是否最适合这项工作?

using System.Threading;

public class DailyTask

    public static void StartJob()
    
        while (true)
        
            string lastRunFile = "lastRun.txt";
            // get the last time the file was written to
            DateTime lastRunTime = new System.IO.FileInfo(lastRunFile).LastWriteTime;
            // get time span since last run
            TimeSpan sinceLastRunTime = DateTime.Today - lastRunTime.Date;
            // if a day has passed
            if (sinceLastRunTime.Days >= 1)
            
                // write anything to the file to update the lastWriteTime
                System.IO.File.WriteAllText(lastRunFile, DateTime.Now.ToString());
                // Do the job
                DoStuff();
            
            else
            
                // Sleep for an hour
                Thread.Sleep(1000 * 60 * 60);
            
        
    

    private static void DoStuff() 
        // Do the daily task
    

我通过以下方式启动线程:

Thread thr = new Thread(DailyTask.StartJob);
thr.Start();

【问题讨论】:

有很多作业调度工具/库 当然还有更好的方法,例如使用 Windows 任务计划程序每小时(或当一天是新的,例如凌晨 12 点)安排一个作业,所以你不需要一个 while 循环全部。但我的理念是“如果它有效,它就会有效”。我目前看到你的实现有很多问题,但正如你所说,你已经做了“简化”,所以除非你发布真实的代码,否则没有必要详细说明。 如果您不想使用特殊的调度库,您应该考虑使用类似DispatchTimer 的东西,这将与 WPF 的 UI 友好,甚至是来自 @987654325 的常规 Timer @命名空间。 @JEL,最好在另一个线程中启动你的程序,所以使用thr.Start() 很好。你也可以使用更现代的Task.Run。我也会对您的代码进行以下改进。 1) 检查 lastRun.txt 文件是否存在,否则 lastRunTime 可能无效。 2) 如果 lastRun.txt 正在被另一个进程使用,则捕获异常,因此您无法读取/写入它。 3)你的Thread.Sleep只存在于ELSE条件中,也就是说,如果你满足IF条件,你就会“完成任务”,然后立即循环回到WHILE循环,不休眠一个小时。 Thread.Sleep(TimeSpan.FromHours(1)); 可能更具可读性 【参考方案1】:

下面的sn-p可以帮到你..

using System.Timers;

        const double intervalinMilliseconds = 86400000; // 1 day in milliseconds

        Timer Timeinterval = new Timer(intervalinMilliseconds);
        Timeinterval.Elapsed += new Dostuff();
        Timeinterval.Enabled = true;

 public void Dostuff(object sender, ElapsedEventArgs e)
    

    

【讨论】:

【参考方案2】:

您可以使用System.Threading.Timer 类。 Timer 构造函数有period 参数,它指定调用回调的时间段。请参阅此处的示例MSDN。

您可以调用DoStuff() 方法作为回调。 这是更好的解决方案,因为它避免了线程休眠。

您还可以使用事件等待句柄 (AutoResetEvent)。见here

类似:

var currenTime = DateTime.Now;
var nextDay = currenTime.AddDays(1);
var periodTillEndOfTheDay = nextDay.Date - currenTime;
var timer = new Timer(x => DoStuff(), null, TimeSpan.Zero, periodTillEndOfTheDay);

【讨论】:

即使你必须使用如此丑陋的构造,你也应该在 WPF 应用程序中使用DisplatcherTimer 而不是System.Threading.Timer 虽然在问题中提到该应用程序是 WPF 应用程序,但要执行的工作似乎是后台。所以Timer也OK。 System.Timers.Timer 在与用户界面 (UI) 线程不同的线程上运行。为了访问用户界面(UI)线程上的对象,需要将操作发布到用户界面(UI)线程的Dispatcher。

以上是关于如何在 C# 中每天激活一次线程的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 中并行运行两个线程 [关闭]

如何在 C# 中修改 Cortana 语音激活命令 (XML)?

在C#中如何使用多线程,每隔几秒去执行一个方法?

如何在多线程环境中只执行一次代码块?

C#如何在BackgroundWorker 后台线程中使用定时器?

如何在 C# 中一次播放多个声音