【问题标题】:Start a Function at Given Time在给定时间启动函数
【发布时间】:2023-03-23 20:20:02
【问题描述】:

如何在 Python 中在给定时间运行函数?

例如:

run_it_at(func, '2012-07-17 15:50:00')

它将在2012-07-17 15:50:00运行函数func

我尝试了sched.scheduler,但它没有启动我的功能。

import time as time_module
scheduler = sched.scheduler(time_module.time, time_module.sleep)
t = time_module.strptime('2012-07-17 15:50:00', '%Y-%m-%d %H:%M:%S')
t = time_module.mktime(t)
scheduler_e = scheduler.enterabs(t, 1, self.update, ())

我能做什么?

【问题讨论】:

  • 什么操作系统?您可能需要使用 python 外部的程序运行它,例如 unix 上的 cron。
  • 为什么不呢?您为enter 设置了什么延迟(假设您尝试过)?
  • 你是如何尝试使用sched.scheduler的?
  • 我用了sched.scheduler,因为我用谷歌搜索了它:)
  • 你打电话给scheduler.run()了吗?

标签: python time scheduler


【解决方案1】:

阅读来自http://docs.python.org/py3k/library/sched.html的文档:

我们需要计算出延迟(以秒为单位)...

from datetime import datetime
now = datetime.now()

然后使用datetime.strptime解析'2012-07-17 15:50:00'(格式字符串留给你)

# I'm just creating a datetime in 3 hours... (you'd use output from above)
from datetime import timedelta
run_at = now + timedelta(hours=3)
delay = (run_at - now).total_seconds()

然后您可以使用delay 传递到threading.Timer 实例,例如:

threading.Timer(delay, self.update).start()

【讨论】:

  • 如果本地时区的 utc 偏移量在 nowrun_at 之间发生变化,例如在 DST 转换前后,本地时间的日期时间算术可能会失败。将本地时间转换为 UTC 或 POSIX 时间戳以执行计算。见Find if 24 hrs have passed between datetimes - Python
  • 你可以直接在timedelta上使用total_secondsdatetime.timedelta(hours=3).total_seconds()
  • 这种方法的准确性如何?我正在寻找小于 10 毫秒的错误
  • @bakalolo:Windows 上的线程调度发生在 1/64 秒 ~ 16 毫秒。它可能不会比这更好。
【解决方案2】:

看看Advanced Python Scheduler,APScheduler:http://packages.python.org/APScheduler/index.html

他们为此用例提供了一个示例: http://packages.python.org/APScheduler/dateschedule.html

from datetime import date
from apscheduler.scheduler import Scheduler

# Start the scheduler
sched = Scheduler()
sched.start()

# Define the function that is to be executed
def my_job(text):
    print text

# The job will be executed on November 6th, 2009
exec_date = date(2009, 11, 6)

# Store the job in a variable in case we want to cancel it
job = sched.add_date_job(my_job, exec_date, ['text'])

【讨论】:

    【解决方案3】:

    可能值得安装这个库:https://pypi.python.org/pypi/schedule,基本上可以帮助您完成您刚才描述的所有事情。这是一个例子:

    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().monday.do(job)
    schedule.every().wednesday.at("13:15").do(job)
    
    while True:
        schedule.run_pending()
        time.sleep(1)
    

    【讨论】:

    • 我搜索了一个特殊的解决方案,这将改变我现在的很多应用程序。我不知道它存在。非常感谢,丹尼尔!
    • 注意schedule不考虑job的持续时间;如果 job 需要 2 分钟,那么 schedule.every().hour.do(job) 实际上将每 62 分钟运行一次。 IMO APScheduler 是一个更好的包。
    • Daniel,OP 要求在特定时间运行功能,你能解释一下我如何用日程安排解决这个问题吗?像 def run_at(f, datetime) -> 在 datetime.now() == datetime 时运行 f
    【解决方案4】:

    以下是 stephenbez 对使用 Python 2.7 的 APScheduler 3.5 版的回答的更新:

    import os, time
    from apscheduler.schedulers.background import BackgroundScheduler
    from datetime import datetime, timedelta
    
    
    def tick(text):
        print(text + '! The time is: %s' % datetime.now())
    
    
    scheduler = BackgroundScheduler()
    dd = datetime.now() + timedelta(seconds=3)
    scheduler.add_job(tick, 'date',run_date=dd, args=['TICK'])
    
    dd = datetime.now() + timedelta(seconds=6)
    scheduler.add_job(tick, 'date',run_date=dd, kwargs={'text':'TOCK'})
    
    scheduler.start()
    print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
    
    try:
        # This is here to simulate application activity (which keeps the main thread alive).
        while True:
            time.sleep(2)
    except (KeyboardInterrupt, SystemExit):
        # Not strictly necessary if daemonic mode is enabled but should be done if possible
        scheduler.shutdown()
    

    【讨论】:

    • @Doezer 但随后的回答对他赢得的声誉无济于事
    【解决方案5】:

    我已经确认开头帖子中的代码有效,只是缺少scheduler.run()。经过测试,它运行预定的事件。所以这是另一个有效的答案。

    >>> import sched
    >>> import time as time_module
    >>> def myfunc(): print("Working")
    ...
    >>> scheduler = sched.scheduler(time_module.time, time_module.sleep)
    >>> t = time_module.strptime('2020-01-11 13:36:00', '%Y-%m-%d %H:%M:%S')
    >>> t = time_module.mktime(t)
    >>> scheduler_e = scheduler.enterabs(t, 1, myfunc, ())
    >>> scheduler.run()
    Working
    >>>
    

    【讨论】:

      【解决方案6】:
      dateSTR = datetime.datetime.now().strftime("%H:%M:%S" )
      if dateSTR == ("20:32:10"):
         #do function
          print(dateSTR)
      else:
          # do something useful till this time
          time.sleep(1)
          pass
      

      只是寻找时间/日期事件触发器: 只要日期“字符串”与更新的“时间”字符串相关联,它就可以作为一个简单的 TOD 函数。您可以将字符串扩展为日期和时间。

      无论是字典顺序还是时间顺序比较, 只要字符串代表一个时间点,字符串也是。

      有人好心地提供了这个链接:

      String Comparison Technique Used by Python

      【讨论】:

        【解决方案7】:

        我遇到了同样的问题:我无法让sched.enterabs 注册的绝对时间事件被sched.run 识别。如果我计算了delaysched.enter 对我有用,但使用起来很尴尬,因为我希望作业在特定时区的特定时间运行。

        就我而言,我发现问题在于sched.scheduler 初始化程序中的默认timefunc 不是time.time(如example),而是time.monotonictime.monotonic 对“绝对”时间表没有任何意义,因为从 docs 来看,“返回值的参考点未定义,因此只有连续调用结果之间的差异才有效。”

        我的解决方案是将调度程序初始化为

        scheduler = sched.scheduler(time.time, time.sleep)

        不清楚你的 time_module.time 究竟是 time.time 还是 time.monotonic,但是当我正确初始化它时它工作正常。

        【讨论】:

          【解决方案8】:
          #everytime you print action_now it will check your current time and tell you should be done
          
          import datetime  
          current_time = datetime.datetime.now()  
          current_time.hour  
          
          schedule = {
              '8':'prep',
              '9':'Note review',
              '10':'code',
              '11':'15 min teabreak ',
              '12':'code',
              '13':'Lunch Break',
              '14':'Test',
              '15':'Talk',
              '16':'30 min for code ',
              '17':'Free',
              '18':'Help ',
              '19':'watever',
              '20':'watever',
              '21':'watever',
              '22':'watever'
          }
          
          action_now = schedule[str(current_time.hour)]
          

          【讨论】:

          • 稍微解释一下会让这个答案更好。
          • 这是一个查找表。问题是寻求一种在特定时间启动功能的方法。您需要添加更多代码才能实现这一点。
          【解决方案9】:

          很难得到这些答案来按照我的需要工作,

          但我得到了这个工作,它精确到 0.01 秒

          from apscheduler.schedulers.background import BackgroundScheduler
              
          sched = BackgroundScheduler()
          sched.start()
          
          def myjob():
              print('job 1 done at: ' + str(dt.now())[:-3])
          
          dt = datetime.datetime
          Future = dt.now() + datetime.timedelta(milliseconds=2000)
          job = sched.add_job(myjob, 'date', run_date=Future)
          

          使用此代码测试计时的准确性: 起初我做了 2 秒和 5 秒的延迟,但想用更准确的测量来测试它,所以我再次尝试了 2.55 秒和 5.55 秒的延迟

          dt = datetime.datetime
          Future = dt.now() + datetime.timedelta(milliseconds=2550)
          Future2 = dt.now() + datetime.timedelta(milliseconds=5550)
          
          def myjob1():
              print('job 1 done at: ' + str(dt.now())[:-3])
          def myjob2():
              print('job 2 done at: ' + str(dt.now())[:-3])
          
          print(' current time: ' + str(dt.now())[:-3])
          print('  do job 1 at: ' + str(Future)[:-3] + ''' 
            do job 2 at: ''' + str(Future2)[:-3])
          job = sched.add_job(myjob1, 'date', run_date=Future)
          job2 = sched.add_job(myjob2, 'date', run_date=Future2)
          

          得到了这些结果:

           current time: 2020-12-10 19:50:44.632
            do job 1 at: 2020-12-10 19:50:47.182 
            do job 2 at: 2020-12-10 19:50:50.182
          job 1 done at: 2020-12-10 19:50:47.184
          job 2 done at: 2020-12-10 19:50:50.183
          

          通过 1 次测试精确到 0.002 秒

          但我确实进行了很多测试,准确度范围从 0.002 到 0.011

          永远不会低于 2.55 或 5.55 秒的延迟

          【讨论】:

            猜你喜欢
            • 2012-07-16
            • 2018-10-15
            • 1970-01-01
            • 2022-06-26
            • 1970-01-01
            • 2014-02-24
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多