【问题标题】:Python - Schedule library - Needs to get busy loopPython - 计划库 - 需要繁忙的循环
【发布时间】:2018-03-09 07:11:32
【问题描述】:

所以我一直在调整日程安排,终于让它发挥作用。我太兴奋了,无法意识到还有另一个问题哈哈。但是现在的问题是,只要主体完成,它就不会结束,我真的找不到解决方案。我知道问题出在 Time.sleep(1) 行上,因为每当我使用 keyboardInterrput 时都会出现一个错误,提示 Time.sleep(1) 是“问题”,我真的找不到解决方案来结束它。

我正在使用来自 github 的时间表:https://github.com/dbader/schedule

while True:
    UserInput = input('To run Schedule task - Press y\nTo run directly - Press n\n')

    if(UserInput == 'y' or UserInput == 'Y'):
        print(Fore.RESET + space)
        TimeUser = input('What time to start script? Format - HH:MM\n')

        schedule.every().day.at(TimeUser).do(main)
        wipe()
        print('Schedule starts at: ''' + TimeUser + ' - Waiting for time...')
        idle = int(round(schedule.idle_seconds()))



        while True:
            schedule.run_pending()
            time.sleep(1)
            idle = int(round(schedule.idle_seconds()))
            if(idle < 6.0) and (idle >= 0.0):
                print('Starting in: ' + str(idle))

    elif(UserInput == 'n' or UserInput == 'N'):
        main()


    print("Wrong input - Try again")

我确实得到了一位非常友善的人的推荐: 调度库需要那个繁忙的循环。这里真正的问题是 OP 如何在不阻塞的情况下运行该繁忙的循环,该库文档中的答案是:在另一个线程中运行它。如果他中断,计划任务将无法完成

https://schedule.readthedocs.io/en/stable/faq.html#how-to-continuously-run-the-scheduler-without-blocking-the-main-thread

而且我仍然不明白如果不阻塞 main 该怎么办。有人知道吗?

【问题讨论】:

    标签: python loops while-loop break schedule


    【解决方案1】:

    在该示例中,它是该模块的标准 Schedule 对象,但扩展了一个额外的方法,您只需调用一次,然后它将在单独的线程中运行。我建议尝试这样做 - 最快的方法可能是创建您自己的子类 Scheduler 的对象并在子类上实现 run_continuously() 方法。然后,您可以在调度程序上调用该方法一次,然后在主线程中执行您喜欢的任何其他操作,而无需定期调用 run_pending()

    按下 Ctrl+C 时出现的错误不是问题 - 它只是抱怨 sleep 在您手动终止时被中断。如果你想根据一些条件自动退出,你可以根据循环中的一些逻辑来执行此操作

    例如while not terminate: 其中 terminate 是您设置的变量,可能是全局变量,可以通过计划任务进行更改。

    这种基于计划的模型的许多实用程序是用于长时间重复运行的后台任务。假设您想执行更多代码,或者您有一些代码需要运行一次并且可能在您进入while 循环之前运行它,或者您想重复运行它并且您也可以将其添加到调度中.

    一些例子

    import schedule
    import threading
    import time
    
    # this is a class which uses inheritance to act as a normal Scheduler,
    # but also can run_continuously() in another thread
    class ContinuousScheduler(schedule.Scheduler):
          def run_continuously(self, interval=1):
                """Continuously run, while executing pending jobs at each elapsed
                time interval.
                @return cease_continuous_run: threading.Event which can be set to
                cease continuous run.
                Please note that it is *intended behavior that run_continuously()
                does not run missed jobs*. For example, if you've registered a job
                that should run every minute and you set a continuous run interval
                of one hour then your job won't be run 60 times at each interval but
                only once.
                """
                cease_continuous_run = threading.Event()
    
                class ScheduleThread(threading.Thread):
                    @classmethod
                    def run(cls):
                        # I've extended this a bit by adding self.jobs is None
                        # now it will stop running if there are no jobs stored on this schedule
                        while not cease_continuous_run.is_set() and self.jobs:
                            # for debugging
                            # print("ccr_flag: {0}, no. of jobs: {1}".format(cease_continuous_run.is_set(), len(self.jobs)))
                            self.run_pending()
                            time.sleep(interval)
    
                continuous_thread = ScheduleThread()
                continuous_thread.start()
                return cease_continuous_run
    
    # example using this custom scheduler that can be run in a separate thread
    your_schedule = ContinuousScheduler()
    your_schedule.every().day.do(print)
    
    # it returns a threading.Event when you start it.
    halt_schedule_flag = your_schedule.run_continuously()
    
    # you can now do whatever else you like here while that runs
    
    # if your main script doesn't stop the background thread, it will keep running
    # and the main script will have to wait forever for it
    
    # if you want to stop it running, just set the flag using set()
    halt_schedule_flag.set()
    
    # I've added another way you can stop the schedule to the class above
    # if all the jobs are gone it stops, and you can remove all jobs with clear()
    your_schedule.clear()
    
    # the third way to empty the schedule is by using Single Run Jobs only
    # single run jobs return schedule.CancelJob
    
    def job_that_executes_once():
        # Do some work ...
        print("I'm only going to run once!")
        return schedule.CancelJob
    
    # using a different schedule for this example to avoid some threading issues
    another_schedule = ContinuousScheduler()
    another_schedule.every(5).seconds.do(job_that_executes_once)
    halt_schedule_flag = another_schedule.run_continuously()
    

    我会注意您是否真的需要为此使用线程 - 如果您只是在寻找程序在完成一次作业后退出,您需要做的就是:

    while schedule.jobs:
        schedule.run_pending()
        time.sleep(1)
    

    并确保您的工作返回 CancelJob。希望该示例对修改有用,已在 repl.it 中进行了测试,并且一切都应该适用于 Python 3。

    【讨论】:

    • 哦,好吧。我现在想明白了哈哈。我确实理解您的意思,但是在使用子类等创建自己的对象时,您迷失了我。你能举个例子吗:)
    • 你确实解释得很好!真的很感激那部分:)
    • 没问题,我真的应该举一些例子。如果到时候没有其他人有的话,我会在稍后有时间的时候做一些:)
    • 谢谢!我希望你真的能用这个来拯救我的星期三!将其作为“待办事项”完成真是太棒了:)谢谢拉赫!
    猜你喜欢
    • 2017-01-18
    • 1970-01-01
    • 2016-07-29
    • 2021-12-20
    • 2016-11-10
    • 2012-01-22
    • 2010-11-14
    • 2013-12-05
    • 2013-12-29
    相关资源
    最近更新 更多