我正在循环中运行一个进程,该进程限制了它每天执行的操作数。当它达到这个限制时,我目前已经让它检查循环中的时间以查看它是否是新日期。
最好的选择是:
- 保持每秒检查时间以获取新日期
- 计算直到午夜的秒数并睡眠该时间长度
- 还有什么?
我正在循环中运行一个进程,该进程限制了它每天执行的操作数。当它达到这个限制时,我目前已经让它检查循环中的时间以查看它是否是新日期。
最好的选择是:
不要将 Thread.Sleep 用于此类事情。使用计时器并计算您需要等待的持续时间。
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 周期的浪费,它会减慢正在运行的所有其他东西。
您应该计算直到午夜的秒数并睡眠那么长时间(尽管我相信睡眠参数需要 ms 而不是 s,因此可能需要进行简单的转换)。
编辑:
计算然后睡觉的另一个好处是,如果用户想通过更改时钟来绕过您的限制,他们将无法这样做(因为时钟读数午夜不会像持续检查那样唤醒进程)。但是,随着对程序内部工作方式的更好理解,用户可以在每次即将达到操作限制时将时钟更改为几乎午夜,从而导致线程在几分钟甚至几秒钟内唤醒。这是一个比你的第一个建议更复杂的利用,但它可以完成。
这就是我如何让线程休眠到明天早上 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);