【问题标题】:C#: How to start a thread at a specific time [duplicate]C#:如何在特定时间启动线程[重复]
【发布时间】:2013-09-07 19:21:00
【问题描述】:

如何在一天中的特定时间(例如 16:00)启动后台线程?

所以当应用程序启动时,线程会一直等到那个时间。但是如果应用程序在该时间之后启动,那么线程将立即运行

ThreadPool.QueueUserWorkItem(MethodtoRunAt1600);

【问题讨论】:

标签: c# .net multithreading


【解决方案1】:

您可以在16:00 设置计时器。我已经回答了一个类似的问题here。 这肯定会对您有所帮助。

private System.Threading.Timer timer;
private void SetUpTimer(TimeSpan alertTime)
{
     DateTime current = DateTime.Now;
     TimeSpan timeToGo = alertTime - current.TimeOfDay;
     if (timeToGo < TimeSpan.Zero)
     {
        return;//time already passed
     }
     this.timer = new System.Threading.Timer(x =>
     {
         this.SomeMethodRunsAt1600();
     }, null, timeToGo, Timeout.InfiniteTimeSpan);
}

private void SomeMethodRunsAt1600()
{
    //this runs at 16:00:00
}

然后设置它使用

SetUpTimer(new TimeSpan(16, 00, 00));

编辑:保留 Timer 的引用,因为无论 Timer 是否处于活动状态,它都会受到垃圾回收的影响。

【讨论】:

  • @SriramSakthivel 嗨,可以在 3 个不同的时间调用该方法吗?
  • @VAAA 设置 3 个不同的计时器或使用单个计时器,一旦触发,使用相同的计时器设置第二个等等。
  • @SriramSakthivel 你能进一步解释一下吗?这将如何工作。以及如何使用它。
  • @Reynan 不,它没有。要将其设置为每天,您需要在 Timer 构造函数的最后一个参数中传递 Timeout.FromDays(1) 而不是 Timeout.InfiniteTimeSpan。另请注意,如果时间已过,您可能需要更改 if 语句,该语句跳过触发计时器。
  • @LeonardAB 我建议改用 windows 任务调度器或石英任务调度器
【解决方案2】:

我会使用像Quartz 这样的作业调度库,或者只是创建控制台应用程序并在一天中的特定时间使用 Windows 任务调度程序运行它。

Why not just use System.Timers.Timer?

  • 定时器没有持久化机制。
  • 定时器的调度不灵活(只能设置开始时间和重复间隔,不能基于日期、时间等设置。
  • 定时器不使用线程池(每个定时器一个线程)
  • 计时器没有真正的管理方案 - 您必须编写自己的机制才能按名称记住、组织和检索您的任务,e

【讨论】:

  • 为什么要为与Timer 无关的事情安装整个库?
  • 为什么要安装一个完整的库,或者创建然后清理一个计时器,一次“等待”机制,即 2 行代码:|
  • @jgauffin:说想要的时间是 0400。在 1600,你设置了一个 12 小时的计时器。在 0200,计时器还有 2 小时的时间。但这是“倒退”日,时钟拨回一小时。所以现在是 0100,计时器将在 0300 触发。同样的事情发生在“Spring Ahead”这一天。计时器将在 0500 时触发,因为时钟提前了。关键是系统时间正确的。错误是假设 12 小时的实时时间总是 12 小时的时钟时间。
  • @jgauffin:您不能为特定时间设置 System.Timers.Timer 或任何其他 .NET 计时器。您只能将它们设置为一段时间。
  • @Damith:你关于定时器不使用线程池的观点是不正确的。定时器不占用线程,除非它的回调函数正在执行,然后它在池线程上执行。如果您创建 100 个计时器,就不会分配 100 个线程。
【解决方案3】:

你可以用计时器来做:

public class OncePerDayTimer : IDisposable
{
    private DateTime _lastRunDate;
    private TimeSpan _time;
    private Timer _timer;
    private Action _callback;

    public OncePerDayTimer(TimeSpan time, Action callback)
    {
        _time = time;
        _timer = new Timer(CheckTime, null, TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1));
        _callback = callback;
    }

    private void CheckTime(object state)
    {
        if (_lastRunDate == DateTime.Today)
            return;

        if (DateTime.Now.TimeOfDay < _time)
            return;

        _lastRunDate = DateTime.Today;
        _callback();
    }

    public void Dispose()
    {
        if (_timer == null)
            return;

        _timer.Dispose();
        _timer = null;
    }
}

【讨论】:

  • 面对夏令时更改,这将失败。它可以延迟一个小时或提前一个小时执行。
  • @JimMischel:不,不会。它检查一天中的时间
  • 我的错误。我现在看到你正在投票。
  • @jgauffin 这是每秒轮询一次吗?对于每天运行一次的进程来说有点矫枉过正。
  • @JMG:你有这么少的 CPU 周期有关系吗?
【解决方案4】:

任何依赖于System.Timers.TimerSystem.Threading.Timer 或任何其他当前存在于 .NET Framework 中的计时器的解决方案在遇到夏令时更改时都会失败。如果您使用这些计时器中的任何一个,则必须进行一些轮询。

Windows 有一个您可以使用的Waitable Timer,但它不受任何框架类的支持。几年前我为它写了一个包装器。我发表的文章已经没有了,但是你可以从http://www.mischel.com/pubs/waitabletimer.zip下载完整的源代码

也就是说,如果您的程序每天只运行一次,或者如果它执行的任务可以从程序的其余部分中分离出来,那么您几乎可以肯定使用计划任务会更好。虽然我从未使用过 Quartz.NET,但根据我从我信任的人那里看到的好评,我推荐它是没有问题的。

【讨论】:

    【解决方案5】:

    一个非常简单的解决方案:

    if (DateTime.Now.Hour > 16)
    {
        MethodtoRunAt1600();
    }
    else
    {
        var next16 = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 16, 0, 0);
        var timer = new Timer(MethodtoRunAt1600, null, next16 - DateTime.Now, TimeSpan.FromHours(24));
        timer.Start()
    }
    

    【讨论】:

      【解决方案6】:

      这是一种安排方法被调用一次的简单方法,可以立即调用,也可以在 16:00 调用。

      var runAt = DateTime.Today + TimeSpan.FromHours(16);
      if(runAt < DateTime.Now)
      {
          MethodtoRunAt1600();    
      }
      else
      {
          var dueTime = runAt - DateTime.Now;
          var timer = new System.Threading.Timer(_ => MethodtoRunAt1600(), null, dueTime, TimeSpan.Zero); 
      } 
      

      【讨论】:

        【解决方案7】:

        如果您正在寻找“快速而肮脏”的东西......那么您可以在线程池中启动您的线程,然后“等待”合适的时间。

        // By the way, this code would be *INSIDE* of the background thread. That's what
        // the sentence above says, but apparently we devs only read code :)
        while (DateTime.Now.TimeOfDay < myDesiredStartTime)
        {
            Thread.Sleep(1000);
        }
        

        【讨论】:

        • 想到有人从 UI 线程调用它...
        • 这是最简单的答案 - 不要让主线程决定何时启动后台线程,只需立即启动后台线程并让它决定何时执行它功能。
        • @MartinMilan - 不,您不会从 UI 线程调用它。显然您没有阅读代码 sn-p 上面的很短的句子:)
        • 没有蒂莫西 - 我不是建议你提倡这个 - 只是我可以想象有人(没有经验)尝试它......蒂莫西 - 满足幽默感......
        【解决方案8】:

        1- 从另一个进程调用您的应用程序

        System.Diagnostics.Process.Start("CMD MyApplication.exe", "/C TIME 16:00");
        

        2- 使用Timer,每1分钟检查一次当前时间。

        3- 在您的应用程序中处理 Windows 时间更改事件,并且每次还检查当前时间更多信息:

        http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents.timechanged%28v=vs.100%29.aspx

        我希望其中一个对你有帮助。

        【讨论】:

          【解决方案9】:

          【讨论】:

            【解决方案10】:

            我们可以这样使用吗?

            DispatcherTimer timer ;
            // When application is started
            if (DateTime.Now.Hour == 16)
            {
               // Start your task
            }
            else
            {
                timer = new DispatcherTimer();
                timer.Interval = new TimeSpan(0, 1, 0);
                timer.Tick += timer_Tick;
                timer.Start();
            }
            

            然后每隔一分钟检查一次..

            void timer_Tick(object sender, EventArgs e)
            {
                if (DateTime.Now.Hour == 16)
                {
                    // Start your task
                }
            }
            

            【讨论】:

            • 我知道这已经有几年了,但是,这不会在一个小时内运行任务 60 次(每分钟一次)吗?
            猜你喜欢
            • 2021-11-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多