python中setInterval的等价物

And*_*rea 20 python multithreading setinterval

我最近发布了一个关于如何推迟在Python中执行函数的问题(类似于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
Run Code Online (Sandbox Code Playgroud)

使用如下

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

foo('bar')
# Will print 'bar' 3 times with 1 second delays
Run Code Online (Sandbox Code Playgroud)

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

  • 它似乎过于复杂,我担心我可能错过了一个更简单/更好的机制
  • 可以在没有第二个参数的情况下调用装饰器,在这种情况下它将永远持续.当我说前言时,我的意思是永远 - 即使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
Run Code Online (Sandbox Code Playgroud)

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

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

foo('bar')
# Will print 'bar' 3 times with 1 second delays
Run Code Online (Sandbox Code Playgroud)

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

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.
Run Code Online (Sandbox Code Playgroud)

jd.*_*jd. 11

您的解决方案对我来说很好.

有几种方法可以与线程进行通信.要命令线程停止,您可以使用threading.Event(),它有一个wait()可以使用的方法而不是time.sleep().

stop_event = threading.Event()
...
stop_event.wait(1.)
if stop_event.isSet():
    return
...
Run Code Online (Sandbox Code Playgroud)

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