有时候,我们想实现一个很简单的定时功能,比如让一个程序在每天早上8点调用某个函数。但是我们不想安装任何第三方库,也不会使用crontab或者任务调度功能,所以想用纯Python来实现。有的同学可能会写这样的代码:importtimeimportdatetimedefrun():print('我是一个需要每天调用的函数')defschedule():target_time=datetime.time(8,0,0)today=datetime.date。today()target_date=today+datetime.timedelta(days=1)target_datetime=datetime.datetime.combine(target_date,target_time)now=datetime.datetime.now()delta=(target_datetime-now).total_seconds()时间.sleep(delta)run()whileTrue:time.sleep(24*3600)run()if__name__=='__main__':schedule()这个程序首先计算明天早上8点出现的秒数.休眠这么多秒后,第一次运行目标函数。然后进入死循环,每隔86400秒,程序调用run函数一次。乍一看,这个程序似乎没有问题。但是如果你每天看它的走时,你会发现随着时间的推移,走时会越来越不准。这是因为运行函数不会立即运行完成。跑步也需要时间。假设程序第一次运行run函数时,确实正好是8:00,run函数运行了2秒。那么,程序休眠86400秒后,时间实际是8:00:02。从第二天开始,每天晚2秒。一个月会迟到一分钟。但实际上,如果我们付出微不足道的代价,就可以避免这种错误的发生,程序代码也会变得更简单:importtimeimportdatetimedefrun():print('我是一个每天都需要调用的函数')defschedule():last_run=NonewhileTrue:now=datetime.datetime.now()ifnow.strftime('%H:%M')=='08:00'andlast_run!=now.date():run()last_run=now.date()time.sleep(1)if__name__=='__main__':schedule()程序在死循环,每秒检查一次,如果当前时间刚好是08:00,最后一次操作不是今天,则调用运行功能并将上次运行时间设置为今天。否则,休眠1秒。这样做相当于每一秒都在检查时间,从而避免了长时间操作造成的时间误差。虽然看起来这个无限循环会消耗很多CPU,但只要你算一算,其实一天只循环86400次。次数不多。但无论如何,专业的事情还是要用专业的工具去做。time.sleep可以用来设置周期性的时间间隔,但其实并不适合做定时任务。因为一个支持定时任务的库,比如Python的schedule或者APScheduler,为了保证定时的准确,他们做了很多工作。一些图书馆甚至使用时间轮之类的数据结构来确保时间的准确性。这不是我们用两三行Python代码就可以做到的。总结如果你可以使用crontab或者任务计划,那么这是最好的选择。其次,使用Python特定的计时模块。最后一次,是用time.sleep来实现的。如果你必须使用time.sleep,你应该尽量缩短检查之间的间隔,避免长时间睡眠。本文转载自微信公众号“闻所未闻的密码”,可通过以下二维码关注。转载请联系UnheardCode公众号。
