38

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

因此,当应用程序启动时,线程将等到那个时间。但是如果应用程序在那之后启动,那么线程将立即运行

ThreadPool.QueueUserWorkItem(MethodtoRunAt1600);

4

10 回答 10

74

您可以在 中设置计时器16:00。我在这里回答了一个类似的问题。那肯定对你有帮助。

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 是否处于活动状态,它都会受到垃圾收集的影响。

于 2013-09-04T10:32:52.710 回答
12

我会使用Quartz之类的 Job Scheduling Library,或者只是创建控制台应用程序并在一天中的特定时间使用 Windows 任务调度程序运行它。

为什么不直接使用 System.Timers.Timer?

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

你可以用计时器来做:

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;
    }
}
于 2013-09-04T10:43:24.313 回答
6

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

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

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

于 2013-09-04T13:16:23.087 回答
2

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

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()
}
于 2013-09-04T10:35:45.980 回答
1

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

// 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);
}
于 2013-09-04T10:33:05.200 回答
1

这是一种安排方法调用一次的简单方法,可以立即调用,也可以在 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); 
} 
于 2013-09-04T10:49:09.723 回答
0

我们可以这样使用吗?

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
    }
}
于 2013-09-04T10:34:36.757 回答
0

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

我希望其中之一对您有所帮助。

于 2013-09-04T10:40:06.267 回答
0

这是我用来实现这种功能的东西。 http://www.codeproject.com/Articles/12117/Simulate-a-Windows-Service-using-ASP-NET-to-run-sc

于 2013-09-04T11:37:55.293 回答