Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/windows/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 执行定期行动_Python_Windows_Timer - Fatal编程技术网

Python 执行定期行动

Python 执行定期行动,python,windows,timer,Python,Windows,Timer,我在Windows上工作。我想每10秒执行一个函数foo()。 如何执行此操作?这将在每次调用foo()之间插入10秒的睡眠时间,如果调用很快完成,这大约是您要求的睡眠时间 import time while True: foo() time.sleep(10) 在后台线程中调用foo()时执行其他操作 import time import sys import threading def foo(): sys.stdout.write('({}) foo\n'.f

我在Windows上工作。我想每10秒执行一个函数
foo()


如何执行此操作?

这将在每次调用
foo()
之间插入10秒的睡眠时间,如果调用很快完成,这大约是您要求的睡眠时间

import time

while True:
    foo()
    time.sleep(10)
在后台线程中调用
foo()
时执行其他操作

import time
import sys
import threading

def foo():
    sys.stdout.write('({}) foo\n'.format(time.ctime()))

def foo_target():
    while True:
        foo()
        time.sleep(10)

t = threading.Thread(target=foo_target)
t.daemon = True
t.start()
print('doing other things...')
如果您打算每10秒在python脚本中运行一次foo(),那么您可以在这些行中执行一些操作

import time

def foo():
    print "Howdy"

while True:
    foo()
    time.sleep(10)
foo()
的末尾,创建一个
计时器,它在10秒后调用
foo()
自身。
因为,
Timer
创建一个新的
thread
来调用
foo()

你可以做其他事情而不被阻止

import time, threading
def foo():
    print(time.ctime())
    threading.Timer(10, foo).start()

foo()

#output:
#Thu Dec 22 14:46:08 2011
#Thu Dec 22 14:46:18 2011
#Thu Dec 22 14:46:28 2011
#Thu Dec 22 14:46:38 2011

下面是一个很好的使用Thread类的实现:

下面的代码更快速、更脏:

from threading import Timer
from time import sleep

def hello():
    print "hello, world"
    t = Timer(3,hello)
    t.start()

t = Timer(3, hello)
t.start() # after 3 seconds, "hello, world" will be printed

# timer will wake up ever 3 seconds, while we do something else
while True:
    print "do something else"
    sleep(10)

您可以在不同的线程中执行任务<代码>线程。计时器将允许您在一段时间后执行一次给定的回调,例如,如果您想执行任务,只要回调返回
True
(这实际上是
glib.timeout\u add
提供的,但您可能没有在windows中安装它)或直到您取消它,您可以使用以下代码:

import logging, threading, functools
import time

logging.basicConfig(level=logging.NOTSET,
                    format='%(threadName)s %(message)s')

class PeriodicTimer(object):
    def __init__(self, interval, callback):
        self.interval = interval

        @functools.wraps(callback)
        def wrapper(*args, **kwargs):
            result = callback(*args, **kwargs)
            if result:
                self.thread = threading.Timer(self.interval,
                                              self.callback)
                self.thread.start()

        self.callback = wrapper

    def start(self):
        self.thread = threading.Timer(self.interval, self.callback)
        self.thread.start()

    def cancel(self):
        self.thread.cancel()


def foo():
    logging.info('Doing some work...')
    return True

timer = PeriodicTimer(1, foo)
timer.start()

for i in range(2):
    time.sleep(2)
    logging.info('Doing some other work...')

timer.cancel()
示例输出:

Thread-1 Doing some work...
Thread-2 Doing some work...
MainThread Doing some other work...
Thread-3 Doing some work...
Thread-4 Doing some work...
MainThread Doing some other work...
注意:并不是每次执行间隔都执行回调。Interval是线程在上一次完成回调和下一次调用回调之间等待的时间。

可能会满足您的需要


P> >考虑使用.< /P> < P>简单地睡眠10秒或使用<代码>线程。定时器(10,FO)< /C>会导致启动时间漂移。(您可能不关心这一点,或者这可能是问题的一个重要来源,具体取决于您的具体情况。)导致这一问题的原因可能有两个——线程的唤醒时间或函数的执行时间不准确

你可以在这篇文章的结尾看到一些结果,但首先是一个如何修复它的示例。您需要跟踪下一次调用函数的时间,而不是实际调用函数的时间,并说明差异

以下是一个稍微有点漂移的版本:

import datetime, threading

def foo():
    print datetime.datetime.now()
    threading.Timer(1, foo).start()

foo()
其输出如下所示:

2013-08-12 13:05:36.483580
2013-08-12 13:05:37.484931
2013-08-12 13:05:38.485505
2013-08-12 13:05:39.486945
2013-08-12 13:05:40.488386
2013-08-12 13:05:41.489819
2013-08-12 13:05:42.491202
2013-08-12 13:05:43.492486
2013-08-12 13:05:44.493865
2013-08-12 13:05:45.494987
2013-08-12 13:05:46.496479
2013-08-12 13:05:47.497824
2013-08-12 13:05:48.499286
2013-08-12 13:05:49.500232
2013-08-12 13:21:45.292565
2013-08-12 13:21:47.293000
2013-08-12 13:21:48.293939
2013-08-12 13:21:49.293327
2013-08-12 13:21:50.293883
2013-08-12 13:21:51.293070
2013-08-12 13:21:52.293393
您可以看到亚秒计数不断增加,因此,开始时间是“漂移”的

这是正确解释漂移的代码:

import datetime, threading, time

next_call = time.time()

def foo():
  global next_call
  print datetime.datetime.now()
  next_call = next_call+1
  threading.Timer( next_call - time.time(), foo ).start()

foo()
其输出如下所示:

2013-08-12 13:05:36.483580
2013-08-12 13:05:37.484931
2013-08-12 13:05:38.485505
2013-08-12 13:05:39.486945
2013-08-12 13:05:40.488386
2013-08-12 13:05:41.489819
2013-08-12 13:05:42.491202
2013-08-12 13:05:43.492486
2013-08-12 13:05:44.493865
2013-08-12 13:05:45.494987
2013-08-12 13:05:46.496479
2013-08-12 13:05:47.497824
2013-08-12 13:05:48.499286
2013-08-12 13:05:49.500232
2013-08-12 13:21:45.292565
2013-08-12 13:21:47.293000
2013-08-12 13:21:48.293939
2013-08-12 13:21:49.293327
2013-08-12 13:21:50.293883
2013-08-12 13:21:51.293070
2013-08-12 13:21:52.293393
在这里你可以看到,在亚秒的时间里不再有任何增加

如果您的事件非常频繁,您可能希望在单个线程中运行计时器,而不是为每个事件启动一个新线程。考虑漂移时,这看起来像:

import datetime, threading, time

def foo():
    next_call = time.time()
    while True:
        print datetime.datetime.now()
        next_call = next_call+1;
        time.sleep(next_call - time.time())

timerThread = threading.Thread(target=foo)
timerThread.start()
但是,应用程序不会正常退出,您需要终止计时器线程。如果希望在应用程序完成时正常退出,而不手动终止线程,则应使用

timerThread = threading.Thread(target=foo)
timerThread.daemon = True
timerThread.start()

这里有一个简单的基于单线程睡眠的版本,它会漂移,但在检测到漂移时会尝试自动更正

注:这仅在满足以下3个合理假设的情况下有效:

  • 时间段远大于正在执行的函数的执行时间
  • 正在执行的函数在每次调用中花费的时间大致相同
  • 调用之间的偏移量小于一秒
  • -


    惊讶地发现,没有找到一个解决方案,使用发电机的时间。我只是为了自己的目的设计了这个

    此解决方案:单线程,每个周期都没有对象实例化,使用生成器进行时间计算,在计时时达到
    time
    模块的精度(不同于我在stack exchange中尝试的几种解决方案)

    注意:对于Python2.x,将下面的
    next(g)
    替换为
    g.next()

    结果,例如:

    hello foo (1421705487.5811)
    hello foo (1421705488.5811)
    hello foo (1421705489.5809)
    hello foo (1421705490.5830)
    hello foo (1421705491.5803)
    hello foo (1421705492.5808)
    hello foo (1421705493.5811)
    hello foo (1421705494.5811)
    hello foo (1421705495.5810)
    hello foo (1421705496.5811)
    hello foo (1421705497.5810)
    hello foo (1421705498.5810)
    hello foo (1421705499.5809)
    hello foo (1421705500.5811)
    hello foo (1421705501.5811)
    hello foo (1421705502.5811)
    hello foo (1421705503.5810)
    

    请注意,这个例子包括一个cpu做其他事情的模拟,每个周期0.3秒。如果你每次都把它改成随机的,那就没关系了。
    yield
    行中的max用于在调用函数的时间超过指定的时间段时保护
    睡眠
    不受负数的影响。在这种情况下,它将立即执行,并在下一次执行的计时中弥补损失的时间。

    我想在等待时做其他事情。有什么方法可以使用信号吗?如果你的
    foo()
    需要未知的时间来完成,你会希望生成一个线程,每10秒执行一次
    foo()
    ,如果有必要,我可以告诉你如何执行。foo只是一个快速调用,还是需要几秒钟才能完成?需要一些时间才能完成一件事需要注意的是开始时间“漂移”。我刚刚运行了一个测试,在大约33次迭代中,我的时间漂移了+0.05秒。我进行了1秒的民意调查,这意味着在不到一分钟的时间里,民意调查结果会有20%的偏差。您可以通过在函数开始时而不是结束时调用
    threading.Timer
    来减少漂移,但前提是导致漂移的是函数持续时间,而不是计时器不可靠。减少漂移的最佳方法是只睡所需的时间,直到下一个预期的运行时间。我将添加一个示例作为另一个答案。这还需要在每个周期实例化一个新对象(在新线程中!)。我找不到一个很好的解决这个问题的方法,但是我已经考虑了一下,我在下面很快发布了一个答案,它使用了一个生成器。这里的内存使用情况如何?感觉就像一个无限递归调用,是吗?这个解决方案有点脆弱。有效负载(
    print
    在这种情况下)引发的任何未捕获异常(例如
    IOError
    )将导致整个计划终止。我更喜欢一种解决方案,它能更优雅地处理这些事情,并在异常原因(如磁盘已满)修复后恢复到原始状态