4

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

4

4 回答 4

3

__del__只要有对 的引用,就不会调用它self,并且您在后台线程本身中有一个这样的引用:在 的self参数中def startThread(self):

您需要将运行后台线程的函数移到类之外。而不是__del__我会推荐例如使用弱引用,如下所示。此代码应该在没有__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)
于 2013-02-20T11:00:47.103 回答
1

根据 gnibbler 的评论,使用上下文管理器进行显式资源释放可能会更好。__del__关于是否应该用于资源释放的意见似乎有所不同。关于这个主题的几个好帖子在这里这里

如果你习惯了像 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.closure辅助函数,该函数将确保close在退出时调用它。

import contextlib

with contextlib.closing(test()):
    # Thread will be active here.
# But not here
于 2013-02-20T11:41:23.837 回答
1

我遇到了同样的问题,终于在另一个问题的答案中找到了这个问题的答案。

使用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()

备注:这可能不是干净地结束你的线程,但是当你退出程序时它会停止它,我想这就是你想要的。

于 2017-01-10T08:02:54.493 回答
0

您忘记在del函数中更改当前 test() 实例的“运行”变量。它应该是

 def __del__(self):
        self.running = False
        print "del"

这应该够了吧。

于 2013-07-26T03:00:36.413 回答