我需要一个基于定时器的事件处理程序,它每X秒运行一次,但是可以随意停止和启动。我在Stack Overflow找到了下面的代码,它绝对适合我的需要,但是Python 3.7.4版本的一个变化引入了一个漏洞,任何线程都不能调用它的“join”方法。
from threading import Timer
class InfiniteTimer():
"""A Timer class that does not stop, unless you want it to."""
def __init__(self, seconds, target):
self._should_continue = False
self.is_running = False
self.seconds = seconds
self.target = target
self.thread = None
def _handle_target(self):
self.is_running = True
self.target()
self.is_running = False
self._start_timer()
def _start_timer(self):
if self._should_continue: # Code could have been running when cancel was called.
self.thread = Timer(self.seconds, self._handle_target)
self.thread.start()
def start(self):
if not self._should_continue and not self.is_running:
self._should_continue = True
self._start_timer()
else:
print("Timer already started or running, please wait if you're restarting.")
def cancel(self):
if self.thread is not None:
self._should_continue = False # Just in case thread is running and cancel fails.
self.thread.cancel()
else:
print("Timer never started or failed to initialize.")
def tick():
print('ipsem lorem')
# Example Usage
t = InfiniteTimer(0.5, tick)
t.start()
当上面的代码运行时,每半秒就会创建一个new _thread.lock,如果我取消并重新启动,就会再次创建一个new _thread.lock。
我做了一些研究,并在https://bugs.python.org/issue43050和https://bugs.python.org/issue37788中找到了一些信息,其中建议您需要“join”线程,以便在使用对象之后能够成功地释放对象。
RuntimeError(“无法加入当前线程”)
我也尝试过在self.thread.start()
和self._start_timer()
之后加入,这两个也会导致异常。
我可以对上面的代码做些什么来完全消除它所产生的所有thread_lock()内存泄漏?
2条答案
按热度按时间2g32fytz1#
从本质上讲,如果不创建无限多的_thread. lock对象,我所尝试做的事情就不可能实现。当前Python的计时器还不能提供我所需要的功能。根据https://docs.python.org/3/library/threading.html上的文档,该类表示一个动作,该动作应该只在经过一定时间后才运行--计时器。
与线程一样,计时器通过调用其start()方法启动。计时器可以通过调用cancel()方法停止(在其操作开始之前)。计时器在执行其操作之前等待的时间间隔可能与用户指定的时间间隔不完全相同。
这意味着Python中的计时器与其他语言(如C#)中的计时器完全不同,在C#中,计时器可以随意停止和启动,可以重复,甚至可以动态更改其执行时间。
我面临的最大问题是每当我重新启动计时器(以便它可以重复),我正在从现有计时器中创建一个新计时器,这意味着新线程是现有线程的子线程-所以垃圾收集器不能释放对象,因为它有一个对子线程的引用。那个子线程得到一个子线程,所以我们最终得到孙子和曾-孙子等等,一个永无止境的线程链,这就是内存泄漏。
我已经通过实现一个包含所需功能的线程类解决了这个问题,如下所示:
创建计时器只需一次,并且在初始化后立即启动,如下所示:
暂停定时器是这样完成的:
或:
恢复计时器的过程如下:
或:
停止计时器并允许其被释放:
可以通过读取变量
mytimer.active
来确定计时器是否处于活动状态希望这对其他有类似需求的人有帮助。
km0tfn4u2#
我有同样的问题,并已解决以下代码.