我正在循环运行一个进程,它每天有一定数量的操作限制。当它达到这个限制时,我目前让它在循环中检查时间,看是否到了新的一天。
那么最好的选择是:
- 每秒钟检查一次时间,以判断是否到了新的一天
- 计算距离午夜还有多少秒,然后等待相应的时间
- 其他什么方法?
我正在循环运行一个进程,它每天有一定数量的操作限制。当它达到这个限制时,我目前让它在循环中检查时间,看是否到了新的一天。
那么最好的选择是:
var now = DateTime.Now;
var tomorrow = now.AddDays(1);
var durationUntilMidnight = tomorrow.Date - now;
var t = new Timer(o=>{/* Do work*/}, null, TimeSpan.Zero, durationUntilMidnight);
用指定的回调函数替换 /* Do Work */
委托,以在指定间隔内恢复工作。
编辑:如评论中所述,如果您假设应用程序等待的“经过时间”将与实际时间相匹配,可能会出现许多问题。因此,如果时间很重要,最好使用较小的轮询间隔来查找时钟是否已达到您希望进行工作的时间。
更好的方法是使用Windows任务计划程序在所需时间运行任务。这比尝试在代码中自己实现要可靠得多。
Windows有一个任务计划程序,可以处理这个任务。创建要完成的程序,然后将其设置为定期任务。
只需计算等待的时间并以异步定时器的方式运行,这样您就可以避免在等待期间额外消耗CPU:
var nextDateStartDateTime = DateTime.Now.AddDays(1).Subtract(DateTime.Now.TimeOfDay);
double millisecondsToWait = (nextDateStartDateTime - DateTime.Now).TotalMilliseconds;
System.Threading.Timer timer = new Timer(
(o) => { Debug.WriteLine("New day comming on"); },
null,
(uint)millisecondsToWait
0);
考虑您提供的两个选项:
每天有60 * 60 * 24 = 86,400秒,因此如果您早期达到限制,您可能会进行大量检查。此外,忙等待是浪费CPU周期的行为,它会减慢运行的所有其他内容。
您应该计算到午夜的秒数并睡眠那么长时间(尽管我认为睡眠参数需要毫秒而不是秒,因此可能需要进行简单的转换)。
编辑:
计算然后睡眠的另一个好处是,如果用户想通过更改时钟来绕过您的限制,他们将无法做到这一点(因为时钟读取午夜不会像持续检查一样唤醒进程)。但是,如果更好地了解您的程序在内部如何工作,用户可以在即将达到操作限制的时候将时钟更改为接近午夜,从而使线程在几分钟甚至几秒钟内唤醒。这比您的第一个建议更复杂的利用,但是它是可行的。
这是我如何使线程睡眠直到明天早上6点
minutesToSleep = (int)(new DateTime(DateTime.Now.AddDays(1).Year, DateTime.Now.AddDays(1).Month, DateTime.Now.AddDays(1).Day, 6, 0, 0) - DateTime.Now).TotalMinutes;
Console.WriteLine("Sleeping for {0} minutes (until tomorrow 6AM)", minutesToSleep);