python中setInterval的等价物

时间:2011-03-03 10:28:25

标签: python multithreading setinterval

我最近发布了一个关于如何推迟Python中函数执行的question(类似于Javascript setTimeout),结果证明这是一个使用threading.Timer的简单任务(好吧,只要该函数不与其他代码共享状态,但这会在任何事件驱动的环境中产生问题)。

现在我正在努力做得更好并模仿setInterval。对于那些不熟悉Javascript的人,setInterval允许每隔x秒重复一次对函数的调用,而不会阻止其他代码的执行。我创建了这个示例装饰器:

import time, threading

def setInterval(interval, times = -1):
    # This will be the actual decorator,
    # with fixed interval and times parameter
    def outer_wrap(function):
        # This will be the function to be
        # called
        def wrap(*args, **kwargs):
            # This is another function to be executed
            # in a different thread to simulate setInterval
            def inner_wrap():
                i = 0
                while i != times:
                    time.sleep(interval)
                    function(*args, **kwargs)
                    i += 1
            threading.Timer(0, inner_wrap).start()
        return wrap
    return outer_wrap

使用如下

@setInterval(1, 3)
def foo(a):
    print(a)

foo('bar')
# Will print 'bar' 3 times with 1 second delays

在我看来它工作正常。我的问题是

  • 看起来过于复杂,我担心我可能错过了一个更简单/更好的机制
  • 可以在没有第二个参数的情况下调用装饰器,在这种情况下它将永远持续下去。当我说foreover时,我的意思是永远 - 即使从主线程调用sys.exit()也不会阻止它,也不会命中Ctrl+c。阻止它的唯一方法是从外部杀死python进程。我希望能够从主线程发送一个停止回调的信号。但我是一个有线程的初学者 - 我怎么能在他们之间进行交流?

编辑如果有人想知道,这是装饰者的最终版本,感谢jd的帮助

import threading

def setInterval(interval, times = -1):
    # This will be the actual decorator,
    # with fixed interval and times parameter
    def outer_wrap(function):
        # This will be the function to be
        # called
        def wrap(*args, **kwargs):
            stop = threading.Event()

            # This is another function to be executed
            # in a different thread to simulate setInterval
            def inner_wrap():
                i = 0
                while i != times and not stop.isSet():
                    stop.wait(interval)
                    function(*args, **kwargs)
                    i += 1

            t = threading.Timer(0, inner_wrap)
            t.daemon = True
            t.start()
            return stop
        return wrap
    return outer_wrap

如上所述,它可以与固定的重复次数一起使用

@setInterval(1, 3)
def foo(a):
    print(a)

foo('bar')
# Will print 'bar' 3 times with 1 second delays

或者可以保持运行直到收到停止信号

import time

@setInterval(1)
def foo(a):
    print(a)

stopper = foo('bar')

time.sleep(5)
stopper.set()
# It will stop here, after printing 'bar' 5 times.

4 个答案:

答案 0 :(得分:10)

你的解决方案对我来说很好。

有几种与线程通信的方法。要命令线程停止,您可以使用threading.Event(),其中wait()方法可以使用time.sleep()代替stop_event = threading.Event() ... stop_event.wait(1.) if stop_event.isSet(): return ...

daemon

要让您的线程在程序终止时退出,请在调用True之前将其start()属性设置为Timer()。这也适用于threading.Thread个对象,因为它们是{{1}}的子类。见http://docs.python.org/library/threading.html#threading.Thread.daemon

答案 1 :(得分:2)

使用递归调用Timer可能有点简单:

from threading import Timer
import atexit

class Repeat(object):

    count = 0
    @staticmethod
    def repeat(rep, delay, func):
        "repeat func rep times with a delay given in seconds"

        if Repeat.count < rep:
            # call func, you might want to add args here
            func()
            Repeat.count += 1
            # setup a timer which calls repeat recursively
            # again, if you need args for func, you have to add them here
            timer = Timer(delay, Repeat.repeat, (rep, delay, func))
            # register timer.cancel to stop the timer when you exit the interpreter
            atexit.register(timer.cancel)
            timer.start()

def foo():
    print "bar"

Repeat.repeat(3,2,foo)

atexit允许用CTRL-C发出停止信号。

答案 2 :(得分:2)

也许这些是python中最简单的setInterval等价物:

 import threading

 def set_interval(func, sec):
    def func_wrapper():
        set_interval(func, sec) 
        func()  
    t = threading.Timer(sec, func_wrapper)
    t.start()
    return t

答案 3 :(得分:0)

这个班级间隔

class ali:
    def __init__(self):
        self.sure = True;

    def aliv(self,func,san):
        print "ali naber";
        self.setInterVal(func, san);

    def setInterVal(self,func, san):

        # istenilen saniye veya dakika aralığında program calışır. 
        def func_Calistir():

            func(func,san);  #calışıcak fonksiyon.
        self.t = threading.Timer(san, func_Calistir)
        self.t.start()
        return self.t


a = ali();
a.setInterVal(a.aliv,5);