我在javascripts中只使用了setInterval
类似于python而且它有点不同,问题是我似乎无法弄清楚如何取消它,因为当我取消它时,它只是一个新的一,并在我取消原始帖子后继续运行那个
def setInterval(sec, func, *args, **kw):
def inner():
func(*args, **kw)
setInterval(sec, func, *args, **kw) # This is where it sends it again
task = threading.Timer(sec, inner)
task.daemon = True
task.start()
return task
正如您所看到的,它可以工作,但是我没有办法取消线程,因为原始版本再次执行并创建一个新版本才能取消它。如何设置它,如果线程被取消,它将不会创建相同原始线程的任何副本?我已经尝试添加一些关键字,然后在其中发送线程,如果它是一种threading.Timer,它取消它,但它似乎没有工作,因为它已经取消原来的副本,它可以取消,任何想法或建议?我只是想想一种方式,所以它知道它是原件的副本然后不执行它但我不确定我将如何实际做到这一点。有什么我可以做的,所以它终止/取消原始线程,并且在它有机会被取消之前不会启动它的新副本吗?这是我尝试做的事情,因为你想告诉我我做错了什么。
def setInterval(sec = None, func = None, *args, **kw):
start = True if type(func) != threading.Timer else func.cancel() # doesn't work anyways
def inner():
func(*args, **kw)
setInterval(sec, func, *args, **kw)
if start == True:
task = thrading.Timer(sec, inner)
task.daemon = True
task.start()
return task
def clearInterval(task):
setInterval(func = task)
myInterval = setInterval(10, print, "Hello, world!")
clearInterval(myInterval) # cancels original, continues to make copies
答案 0 :(得分:1)
在运行前取消Timer
会阻止它调用其回调函数。但如果它已经被唤醒,取消它已经太晚了。而且,由于您的代码在回调中创建了 new Timer
,因此新的计时器不会知道它应该被取消。
因此,你需要配合回调函数,让它访问一些标志,让它知道它被取消了(例如,使用可变的全局或闭包变量,函数属性或默认参数值) )。当然,这个变量需要同步,这意味着你在Lock
下阅读它,或者你有竞争条件。 (在CPython中,由于GIL,该种族的最坏情况应偶尔运行一次,但在不同的实现中,计时器线程(回调运行的地方)可能永远不会看到更新的值。)
然而,这将变得复杂。您可能最好先将Timer
课程扩展为RepeatingTimer
。然后,如果你真的想要,你可以用简单的setInterval
/ clearInterval
函数包装它。
ActiveState上的大量配方和PyPI上的包添加了repeat
标志或等价物,还做了其他很好的事情,比如使用单个线程而不是为每个间隔创建一个新线程。但如果你想知道如何自己做,这很容易。事实上,threading
docs有threading.py
source的链接,因为它可以作为示例代码使用,你可以看到琐碎的Timer
是多么的,所以你甚至可以自己重新实现它。
但是,让我们用子类来做。
class RepeatableTimer(threading.Timer):
def __init__(self, interval,
function, args=None, kwargs=None, repeat=False):
super(RepeatableTimer, self).__init__(interval, function, args, kwargs)
self.repeat = repeat
self.lock = threading.Lock()
def cancel(self):
with self.lock:
self.repeat = False
super(RepeatableTimer, self).cancel()
def run(self):
while True:
self.finished.clear()
super(RepeatableTimer, self).run()
with self.lock:
if not self.repeat:
break
我认为从头开始实施它实际上会更简单,因为您不必担心重置Event
,但无论如何,这都有效。
如果您想延长此项,而不是repeat
标志,那么times
整数(-1
为"永远重复&#34 ;)在JavaScript中,这是微不足道的。
无论如何,现在您可以将其包含在setInterval
和clearInterval
函数中:
def setInterval(sec=None, func=None, *args, **kw):
task = RepeatableTimer(sec, func, args, kw, repeat=True)
task.daemon = True
task.start()
return task
def clearInterval(task):
task.cancel()
虽然注意到clearInterval = RepeatableTimer.cancel
也会起作用。 (在Python 2.x中,这将是一个未绑定的方法与一个函数,但它仍然可以工作相同,除了提供不同的错误消息,如果你用错误的args调用它。在3.x,没有区别完全没有。)
如果您真的希望通过拨打clearInterval
来setInterval
来完成整个过程,那么您可以,但至少要清理一下使用isinstance
而不是type
的{{1}},并且当你可以在一个if
中完成所有操作时,不要尝试设置你在第二个if
中使用的标记:
def setInterval(sec=None, func=None, *args, **kw):
if isinstance(func, RepeatableTimer):
task.cancel()
else:
task = RepeatableTimer(sec, func, args, kw, repeat=True)
task.daemon = True
task.start()
return task
def clearInterval(task):
setInterval(func=task)
但我不知道你认为那会给你买什么。
无论如何,这是验证其有效的测试:
myInterval = setInterval(1, print, "Hello, world!")
time.sleep(3)
clearInterval(myInterval)
time.sleep(5)
这应该通常打印"你好,世界!" 2或3次,偶尔4次,但从不7或8次像一个不可取消的计时器。