【问题标题】:How to have a thread activate once a day in C#如何在 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)); 可能更具可读性

标签: c# .net wpf multithreading timer


【解决方案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。
    猜你喜欢
    • 2011-01-16
    • 1970-01-01
    • 2018-09-11
    • 2017-04-02
    • 2018-09-01
    • 1970-01-01
    • 2010-09-21
    • 1970-01-01
    • 2016-12-24
    相关资源
    最近更新 更多