我想在主程序停止时停止Python线程。它是连接到服务器的类。连接由后台线程维护,前台线程回答回调。以下是一个最小的例子。
#!/usr/bin/python
import time, threading
class test():
running = False
def __init__(self):
print "init"
self.running = True
self.thread = threading.Thread(target = self.startThread)
self.thread.start()
def __del__(self):
running = False
print "del"
def startThread(self):
print "thread start"
while self.running:
time.sleep(1)
print "thread running"
a = test()
当程序结束时,我会天真地期望调用__del __(),以便可以通知后台线程停止,但是在后台线程停止后我不会被调用。显式调用某个函数不是一个选项,因为该类是由其他人使用的,我不想强迫他们使用一些额外的代码行。
答案 0 :(得分:2)
__del__
的引用,就不会调用 self
,并且在后台线程本身中有一个这样的引用:在self
def startThread(self):
参数中
您需要将运行后台线程的函数移到类外部。而不是__del__
我建议例如使用weakref,如下所示。此代码应该在没有__del__()
方法且不使用self.running
属性的情况下工作。
self.thread = threading.Thread(target=run_me, args=(weakref.ref(self),))
...
def run_me(weak_self):
"Global function"
while True:
self = weak_self()
if self is None: break # no more reference to self
...
del self # forget this reference for now
time.sleep(1)
答案 1 :(得分:1)
我遇到了同样的问题,最后在另一个question的答案中找到了这个问题的答案。
的文档所以你的代码就是这样:
#!/usr/bin/python
import time, threading
class test():
def __init__(self):
print "init"
self.thread = threading.Thread(target = self.startThread)
self.thread.daemon = True
self.thread.start()
def startThread(self):
print "thread start"
while True:
time.sleep(1)
print("thread running")
a = test()
备注:这可能不会干净地结束您的主题,但是当您退出程序时会停止它,我想这就是您要找的内容。
答案 2 :(得分:0)
根据gnibbler的评论,使用上下文管理器进行显式资源释放可能会更好。对__del__
是否应该用于资源重新分配,意见似乎有所不同。关于此主题的几篇好帖子是here和here。
如果你习惯使用像C ++那样使用RAII的语言,有时候很难习惯Python中的析构函数可能没有被调用的时候,如果有的话,通常会被调用因为引用计数和垃圾收集的工作原理。
因此,Python中的常用方法是使用上下文管理器,该管理器可用于提供资源的显式释放。
一个简单的线程示例可能如下所示(未经测试):
#!/usr/bin/python
import time, threading
class test():
def __init__(self):
print "init"
self.stop_event = threading.Event()
self.thread = threading.Thread(target = self.startThread)
self.thread.start()
def startThread(self):
print "thread start"
while not self.stop_event.isSet():
time.sleep(1)
print "thread running"
def close(self):
# Request thread to stop.
self.stop_event.set()
# Wait for thread to exit.
self.thread.join()
def __enter__(self):
# Nothing to do, thread already started. Could start
# thread here to enforce use of context manager.
def __exit__(self, exc_type, exc_value, traceback):
self.close()
然后在上下文管理器中使用test()
类:
with test():
# Thread will be active here.
pass
# Thread will have been stopped and joined.
或者,使用Python contextlib.closing帮助函数,这将确保在退出时调用close
。
import contextlib
with contextlib.closing(test()):
# Thread will be active here.
# But not here
答案 3 :(得分:0)
您忘记在 del 函数中更改当前test()实例的“running”变量。它应该是
def __del__(self):
self.running = False
print "del"
这应该可以解决问题。