Python 每x秒重复执行一个函数的最佳方式是什么?
我希望永远每隔60秒在Python中重复执行一个函数(就像在Objective C中执行一个函数一样)。这段代码将作为守护进程运行,就像每分钟使用cron调用python脚本一样,但不需要用户进行设置 在中,解决方案似乎仅在x秒内有效。我不需要这样的高级功能,所以也许类似的东西可以工作Python 每x秒重复执行一个函数的最佳方式是什么?,python,timer,Python,Timer,我希望永远每隔60秒在Python中重复执行一个函数(就像在Objective C中执行一个函数一样)。这段代码将作为守护进程运行,就像每分钟使用cron调用python脚本一样,但不需要用户进行设置 在中,解决方案似乎仅在x秒内有效。我不需要这样的高级功能,所以也许类似的东西可以工作 while True: # Code executed here time.sleep(60) 此代码是否存在任何可预见的问题?如果您的程序还没有事件循环,请使用实现通用事件调度器的模块 imp
while True:
# Code executed here
time.sleep(60)
此代码是否存在任何可预见的问题?如果您的程序还没有事件循环,请使用实现通用事件调度器的模块
import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc):
print("Doing stuff...")
# do your stuff
s.enter(60, 1, do_something, (sc,))
s.enter(60, 1, do_something, (s,))
s.run()
如果您已经在使用事件循环库,如
asyncio
、trio
、tkinter
、PyQt5
、gobject
、kivy
,以及许多其他库,只需使用现有事件循环库的方法安排任务,相反。它与cron之间的主要区别在于异常将永久杀死守护进程。你可能想用一个异常捕捉器和记录器来包装。 你可能想考虑哪一个是python网络库,它实现了.
虽然“While True:sleep(60)”可能会起作用,但Twisted可能已经实现了您最终需要的许多功能(后台监控、日志记录或异常处理,正如bobince所指出的),并且可能是一个更健壮的解决方案,我相信这是一种更简单的方法:
import time
def executeSomething():
#code here
time.sleep(60)
while True:
executeSomething()
通过这种方式执行代码,然后等待60秒,然后再次执行,等待,执行,等等。。。
没有必要把事情复杂化:D不久前我也遇到过类似的问题。可能有帮助吗 对于v0.2,以下代码段有效
import cronus.beat as beat
beat.set_rate(2) # 2 Hz
while beat.true():
# do some time consuming work here
beat.sleep() # total loop duration would be 0.5 sec
将时间循环锁定到系统时钟,如下所示:
import time
starttime = time.time()
while True:
print "tick"
time.sleep(60.0 - ((time.time() - starttime) % 60.0))
如果您希望使用非阻塞方式定期执行函数,而不是阻塞无限循环,我会使用线程计时器。这样,您的代码可以继续运行并执行其他任务,并且仍然每n秒调用一次您的函数。我经常使用这种技术来打印长时间、CPU/磁盘/网络密集型任务的进度信息 下面是我在类似问题中发布的代码,带有start()和stop()控件: 用法:
from time import sleep
def hello(name):
print "Hello %s!" % name
print "starting..."
rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start()
try:
sleep(5) # your long-running job goes here...
finally:
rt.stop() # better in a try/finally block to make sure the program ends!
特点:
- 仅标准库,无外部依赖项
和start()
可以安全地多次调用,即使计时器已经启动/停止stop()
- 要调用的函数可以具有位置参数和命名参数
- 您可以随时更改
,它将在下次运行后生效。对于间隔
,args
甚至kwargs
函数也一样李>
import threading
import time
class RepeatedTimer(object):
def __init__(self, interval, function, *args, **kwargs):
self._timer = None
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.is_running = False
self.next_call = time.time()
self.start()
def _run(self):
self.is_running = False
self.start()
self.function(*self.args, **self.kwargs)
def start(self):
if not self.is_running:
self.next_call += self.interval
self._timer = threading.Timer(self.next_call - time.time(), self._run)
self._timer.start()
self.is_running = True
def stop(self):
self._timer.cancel()
self.is_running = False
示例用法(摘自MestreLion的答案):
我使用它每小时引发60个事件,大多数事件在整分钟后以相同的秒数发生:
import math
import time
import random
TICK = 60 # one minute tick size
TICK_TIMING = 59 # execute on 59th second of the tick
TICK_MINIMUM = 30 # minimum catch up tick size when lagging
def set_timing():
now = time.time()
elapsed = now - info['begin']
minutes = math.floor(elapsed/TICK)
tick_elapsed = now - info['completion_time']
if (info['tick']+1) > minutes:
wait = max(0,(TICK_TIMING-(time.time() % TICK)))
print ('standard wait: %.2f' % wait)
time.sleep(wait)
elif tick_elapsed < TICK_MINIMUM:
wait = TICK_MINIMUM-tick_elapsed
print ('minimum wait: %.2f' % wait)
time.sleep(wait)
else:
print ('skip set_timing(); no wait')
drift = ((time.time() - info['begin']) - info['tick']*TICK -
TICK_TIMING + info['begin']%TICK)
print ('drift: %.6f' % drift)
info['tick'] = 0
info['begin'] = time.time()
info['completion_time'] = info['begin'] - TICK
while 1:
set_timing()
print('hello world')
#random real world event
time.sleep(random.random()*TICK_MINIMUM)
info['tick'] += 1
info['completion_time'] = time.time()
但在60分钟结束时,你会有60个滴答声;其中大多数都会发生在您喜欢的时间的正确偏移处
在我的系统中,我得到了<1/20秒的典型漂移,直到需要修正为止
这种方法的优点是能够分辨时钟漂移;这可能会导致问题,如果你正在做的事情,如追加一个项目每勾,你希望每小时追加60个项目。不考虑漂移可能导致次要迹象,比如移动平均值,考虑过去太深的数据,导致错误的输出。 一个可能的答案:
import time
t=time.time()
while True:
if time.time()-t>10:
#run your task here
t=time.time()
e、 显示当前本地时间
import datetime
import glib
import logger
def get_local_time():
current_time = datetime.datetime.now().strftime("%H:%M")
logger.info("get_local_time(): %s",current_time)
return str(current_time)
def display_local_time():
logger.info("Current time is: %s", get_local_time())
return True
# call every minute
glib.timeout_add(60*1000, display_local_time)
我使用Tkinter after()方法,它不会“偷走游戏”(就像前面介绍的sched模块),也就是说,它允许其他东西并行运行:
import Tkinter
def do_something1():
global n1
n1 += 1
if n1 == 6: # (Optional condition)
print "* do_something1() is done *"; return
# Do your stuff here
# ...
print "do_something1() "+str(n1)
tk.after(1000, do_something1)
def do_something2():
global n2
n2 += 1
if n2 == 6: # (Optional condition)
print "* do_something2() is done *"; return
# Do your stuff here
# ...
print "do_something2() "+str(n2)
tk.after(500, do_something2)
tk = Tkinter.Tk();
n1 = 0; n2 = 0
do_something1()
do_something2()
tk.mainloop()
dosomething1()
和dosomething2()
可以以任何间隔速度并行运行。这里,第二个将以两倍的速度执行。还要注意,我使用了一个简单的计数器作为终止任一函数的条件。您可以使用您喜欢的任何其他条件,或者如果您希望在程序终止之前运行函数(例如时钟),则可以不使用任何其他条件
如果要在不阻塞剩余代码的情况下执行此操作,可以使用此选项让其在自己的线程中运行:
import threading
threading.Thread(target=lambda: every(5, foo)).start()
此解决方案结合了其他解决方案中很少结合的几个功能:
- 异常处理:在这个级别上,尽可能正确地处理异常,即。E在不中止程序的情况下,为调试目的登录
- 无链接:您在许多答案中发现的常见链式实现(用于安排下一个事件)在以下方面是脆弱的,即如果调度机制(
或其他什么)中出现任何错误,这将终止链。即使问题的原因已经确定,也不会发生进一步的处决。相比之下,使用简单的threading.Timer
进行简单的循环和等待要健壮得多sleep()
- 无漂移:我的解决方案精确跟踪它应该运行的时间。不存在依赖于执行时间的漂移(与许多其他解决方案一样)
- 跳过:如果一次执行花费太多时间,我的解决方案将跳过任务(例如,每5秒执行一次X,但X花费6秒)。这是标准的cron行为(有很好的理由)。然后,许多其他解决方案只是连续几次执行该任务,而没有任何延迟。对于大多数情况(例如清理任务),这是不希望的。如果愿意,只需使用
next\u time+=delay
import time t=time.time() while True: if time.time()-t>10: #run your task here t=time.time()
import datetime import glib import logger def get_local_time(): current_time = datetime.datetime.now().strftime("%H:%M") logger.info("get_local_time(): %s",current_time) return str(current_time) def display_local_time(): logger.info("Current time is: %s", get_local_time()) return True # call every minute glib.timeout_add(60*1000, display_local_time)
import Tkinter def do_something1(): global n1 n1 += 1 if n1 == 6: # (Optional condition) print "* do_something1() is done *"; return # Do your stuff here # ... print "do_something1() "+str(n1) tk.after(1000, do_something1) def do_something2(): global n2 n2 += 1 if n2 == 6: # (Optional condition) print "* do_something2() is done *"; return # Do your stuff here # ... print "do_something2() "+str(n2) tk.after(500, do_something2) tk = Tkinter.Tk(); n1 = 0; n2 = 0 do_something1() do_something2() tk.mainloop()
import time, traceback def every(delay, task): next_time = time.time() + delay while True: time.sleep(max(0, next_time - time.time())) try: task() except Exception: traceback.print_exc() # in production code you might want to have this instead of course: # logger.exception("Problem while executing repetitive task.") # skip tasks if we are behind schedule: next_time += (time.time() - next_time) // delay * delay + delay def foo(): print("foo", time.time()) every(5, foo)
import threading threading.Thread(target=lambda: every(5, foo)).start()
''' tracking number of times it prints''' import threading global timeInterval count=0 def printit(): threading.Timer(timeInterval, printit).start() print( "Hello, World!") global count count=count+1 print(count) printit if __name__ == "__main__": timeInterval= int(input('Enter Time in Seconds:')) printit()
class RepeatedTimer(object): def __init__(self, first_interval, interval, func, *args, **kwargs): self.timer = None self.first_interval = first_interval self.interval = interval self.func = func self.args = args self.kwargs = kwargs self.running = False self.is_started = False def first_start(self): try: # no race-condition here because only control thread will call this method # if already started will not start again if not self.is_started: self.is_started = True self.timer = Timer(self.first_interval, self.run) self.running = True self.timer.start() except Exception as e: log_print(syslog.LOG_ERR, "timer first_start failed %s %s"%(e.message, traceback.format_exc())) raise def run(self): # if not stopped start again if self.running: self.timer = Timer(self.interval, self.run) self.timer.start() self.func(*self.args, **self.kwargs) def stop(self): # cancel current timer in case failed it's still OK # if already stopped doesn't matter to stop again if self.timer: self.timer.cancel() self.running = False
import schedule import time def job(): print("I'm working...") schedule.every(10).minutes.do(job) schedule.every().hour.do(job) schedule.every().day.at("10:30").do(job) schedule.every(5).to(10).minutes.do(job) schedule.every().monday.do(job) schedule.every().wednesday.at("13:15").do(job) schedule.every().minute.at(":17").do(job) while True: schedule.run_pending() time.sleep(1)
import threading, time def print_every_n_seconds(n=2): while True: print(time.ctime()) time.sleep(n) thread = threading.Thread(target=print_every_n_seconds, daemon=True) thread.start()
#Tue Oct 16 17:29:40 2018 #Tue Oct 16 17:29:42 2018 #Tue Oct 16 17:29:44 2018
pip install apscheduler
from apscheduler.schedulers.background import BlockingScheduler def print_t(): pass sched = BlockingScheduler() sched.add_job(print_t, 'interval', seconds =60) #will do the print_t work for every 60 seconds sched.start()
import time while True: print("this will run after every 30 sec") #Your code here time.sleep(30)
def print_every_5_seconds_have_passed_exit_eventually(): """ https://stackoverflow.com/questions/3393612/run-certain-code-every-n-seconds https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds :return: """ opts = argparse.Namespace(start=time.time()) next_time_to_print = 0 while True: current_time_passed = time.time() - opts.start if current_time_passed >= next_time_to_print: next_time_to_print += 5 print(f'worked and {current_time_passed=}') print(f'{current_time_passed % 5=}') print(f'{math.floor(current_time_passed % 5) == 0}')
starting __main__ at __init__ worked and current_time_passed=0.0001709461212158203 current_time_passed % 5=0.0001709461212158203 True worked and current_time_passed=5.0 current_time_passed % 5=0.0 True worked and current_time_passed=10.0 current_time_passed % 5=0.0 True worked and current_time_passed=15.0 current_time_passed % 5=0.0 True