使用内置sched模块的非阻塞scheduler.run()方法?

时间:2017-01-20 00:46:38

标签: python python-3.x asynchronous nonblocking built-in

我想了解如何在方法scheduler.run(blocking=True)中使用可选参数blocking。任何实际/现实世界的例子都会非常有用。

根据我迄今为止所做的研究,blocking可选参数的意图是非阻塞或异步应用 [1] [2 ] 。下面是schduler的主要运行循环(来自python 3.6库sched.py)。完成代码后,我注意到只要blocking设置为False,就会立即返回目标时间和当前时间之间的时差,除非目标时间已经过去,在这种情况下将执行操作

while True:
    with lock:
        if not q:
            break
        time, priority, action, argument, kwargs = q[0]
        now = timefunc()
        if time > now:
            delay = True
        else:
            delay = False
            pop(q)
    if delay:
        if not blocking:
            return time - now
        delayfunc(time - now)
    else:
        action(*argument, **kwargs)
        delayfunc(0)   # Let other threads run

在我看来,非阻塞设计要求我继续运行调度程序,直到队列清理为止。因此,我正在考虑自己维护一个任务队列并继续将scheduler.run任务推入队列(如下面的代码所示)。这是一个理想的设计吗?使用非阻塞调度程序的正确方法是什么?

def action():
    print('action at: ', datetime.now())

if __name__ == '__main__':
    s = sched.scheduler(time.time)
    target_time = datetime.now() + timedelta(seconds=5)
    s.enterabs(target_time.timestamp(), 1, action)
    run = functools.partial(s.run, blocking=False)
    taskq = deque()
    taskq.append(run)
    while taskq:
        task = taskq.popleft()
        result = task()
        print(result)
        if result:
            taskq.append(run)
            time.sleep(1)

    print('end tasks')

[1] What’s New In Python 3.3

[2] Issue13449: sched - provide an "async" argument for run() method

1 个答案:

答案 0 :(得分:1)

一个老问题,但是我刚刚实现了一些非常有效地使用非阻塞版本的东西。

blocking = True中的sched.scheduler.run时,它将调用delayfunc作为直到下一个事件的时间差。

如果您的应用程序在t = 0A安排了一个事件t = 10,但是另一个线程在t = 1安排了一个事件{{1, }} B。在这种情况下,

t = 5

如果您的主线程只是在循环中调用s = sched.scheduler(time.time) # Spawn threads which enter A and B into s while True: s.run(True) ,则在sched.scheduler.run(blocking=True)处它将调用t = 0,因为它只看到在delayfunc(10)之前还有10个时间单位。主线程要等到t = 10才唤醒,这时它将看到错过了A,晚B运行5个时间单位,然后在{{之后运行B 1}}。

要解决此问题,您可以将主线程更改为如下形式:

A

此代码将跟踪所有当前事件,然后休眠直到下一个事件,或者如果没有下一个事件,或者如果下一个事件太遥远,则将休眠1秒钟。

理想情况下,调度程序将使用条件变量实现,以确保是否有新事件到达优先级队列的最前面,并且它可以等待该变量,而不是仅休眠到下一个事件。这将是最有效,最准确的时间。