python3 sched:运行后调度事件()

时间:2017-12-31 15:44:55

标签: python python-3.x

在调用scheduler.enter后使用scheduler.run调度事件时,在触发运行调度程序之前输入的至少一个事件之前,不会触发这些事件。这是为了吗?

import sched
import threading
import time

now = time.time()

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


def fire(name):
    print('EVENT:', name, time.time() - now)


def start():
    t = threading.Thread(target=scheduler.run)
    t.start()


###################################
# when scheduling all before start() everything works as expected.

# scheduler.enter(4, 1, fire, ('D',))
# scheduler.enter(3, 1, fire, ('C',))
# scheduler.enter(2, 1, fire, ('B',))
# scheduler.enter(1, 1, fire, ('A',))
# start()
#
# EVENT: A 1.0
# EVENT: B 2.0
# EVENT: C 3.0
# EVENT: D 4.0

###################################
# here I'd expect event 'A' to fire after one second. But it is
# not fired until at least one of the events scheduled before run() 
# is fired.

# scheduler.enter(2, 1, fire, ('B',))
# scheduler.enter(4, 1, fire, ('D',))
# start()
# scheduler.enter(1, 1, fire, ('A',))
# scheduler.enter(3, 1, fire, ('C',))
#
# EVENT: A 2.005021572113037
# EVENT: B 2.005021572113037
# EVENT: C 3.0050315856933594
# EVENT: D 4.0050413608551025

###################################
# starting before any event is scheduled is not possible,
# because run() returns directly.
# 
# start()
# scheduler.enter(3, 1, fire, ('C',))
# scheduler.enter(2, 1, fire, ('B',))
# scheduler.enter(1, 1, fire, ('A',))
#
# -- no events fired.

2 个答案:

答案 0 :(得分:3)

启动调度程序时,它会查找到下一个事件的延迟,并使用该值调用delayfunc(time.sleep())。在delayfunc返回之前,调度程序无法触发任何其他事件。

我对sched模块没有任何解决方法。它的设计似乎是基于这样的想法:新事件将从现有事件的处理程序中添加,而不是来自一个单独的线程(事实上,它甚至不支持在多线程环境中使用,直到Python 3.3 )。使用新的async内容可能是更好的方法,但我没有任何特别的建议。

答案 1 :(得分:0)

请记住,如果您可以将任务分解为定期重复的固定工作,也可以使用schedule

但是在这种情况下,我的解决方案是如图所示子类化调度程序,并使用廉价的私有函数进行轮询。这使调度程序成为永久性的,并且(至少)以轮询间隔的粒度“监听”更新。我设置了一个可配置的轮询速率,默认为每秒4次-非常适合GUI反馈。在生产环境中,正在运行的线程应为守护程序,以免干扰终止请求。这是您代码的修改版本。准备使用时,从民意调查中删除print('tick')

import sched
import threading
import time

now = time.time()

class scheduler_with_polling(sched.scheduler):
    def __init__(self, timefn, waitfn, **kwargs):
        super().__init__(timefn, waitfn)
        self.polling_interval = kwargs.get('polling_interval', 0.25)

    def run(self):
        self.enter(self.polling_interval, 1, self.__poll)
        super().run()

    def __poll(self):
        print('tick') # remove for production
        self.enter(self.polling_interval, 1, self.__poll)
        pass


scheduler = scheduler_with_polling(time.time, time.sleep, polling_interval=0.2)

def fire(name):
    print('EVENT:', name, time.time() - now)


def start():
    t = threading.Thread(target=scheduler.run) # use daemon=True for production
    t.start()

scheduler.enter(2, 1, fire, ('B',))
scheduler.enter(4, 1, fire, ('D',))
start()
scheduler.enter(1, 1, fire, ('A',))
scheduler.enter(3, 1, fire, ('C',))