Python线程,线程不通知停止

时间:2013-02-20 09:32:54

标签: python python-multithreading

我想在主程序停止时停止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 __(),以便可以通知后台线程停止,但是在后台线程停止后我不会被调用。显式调用某个函数不是一个选项,因为该类是由其他人使用的,我不想强​​迫他们使用一些额外的代码行。

4 个答案:

答案 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的答案中找到了这个问题的答案。

使用daemon = True标志。 3.x2.x

的文档

所以你的代码就是这样:

#!/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__是否应该用于资源重新分配,意见似乎有所不同。关于此主题的几篇好帖子是herehere

如果你习惯使用像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"

这应该可以解决问题。