在调用函数时,结束这个线程的最佳方法是什么?

1 投票
3 回答
775 浏览
提问于 2025-04-16 16:41

我在处理这个队列时遇到了一些麻烦:

import Queue
import threading

class test(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.request_queue = Queue.Queue()

    def addtoqueue(self, item):
        self.request_queue.put(item)

    def run(self):
        while True:
            item = self.request_queue.get(True)
            print item

这个简单的类实现了一个线程队列。调用 test::addtoqueue 方法会把一个项目添加到队列中。线程会等待队列中有新项目被添加,然后立即打印出来,并继续等待下一个项目。

我遇到的问题是应用程序关闭时,怎么才能优雅地结束这个线程?我可以使用条件变量,但我该如何同时等待条件变量的通知和队列中新项目的到来呢?

3 个回答

1

我建议你修改一下你的while循环的条件,让它检查一个本地变量。同时,添加一个“杀死开关”,这样外部程序就可以关闭这个线程。你可能还需要扩展一下kill_me,以便优雅地处理对象和它的队列(比如,如果你想在下次运行时保存这个队列)。

编辑 我还在里面添加了一个has_finished变量,这样kill_me就可以阻止主进程线程。这应该能让线程在返回主流程之前先退出。

我可能把事情搞得有点复杂了;)

class test(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.request_queue = Queue.Queue()
        self.is_running = True
        self.has_finished = False   

    def addtoqueue(self, item):
        self.request_queue.put(item)

    def kill_me(self):
        self.is_running = False
        while not self.has_finished:
            pass

    def run(self):
        while self.is_running:
            item = self.request_queue.get(True)
            print item
        self.has_finished = True
1

做最简单的事情,看看能不能成功——在这个情况下,可能就是使用一个哨兵(Sentinel)。虽然 threading 是受到 Java 线程库的启发,但在 Python 中,最简单的方法并不是像 Java 那样去继承 threading.Thread,而是直接把一个函数和它的参数传给 threading.Thread()

DONE = object() # Sentinel

def run(queue):
    while True:
        item = queue.get()
        queue.task_done()
        if item is DONE:
            break
        print item

request_queue = Queue.Queue()
some_thread = Thread(target=run, args=(request_queue,))

some_thread.start()

request_queue.put('hey')
request_queue.put('joe')
request_queue.put(DONE)
1

你可以给线程发送一些“毒药”来结束它:

poison = None # something you wouldn't normally put in the Queue

class test(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.request_queue = Queue.Queue()

    def kill(self):
        self.addtoqueue(poison)

    def addtoqueue(self, item):
        self.request_queue.put(item)

    def run(self):
        while True:
            item = self.request_queue.get(True)
            if item is poison:
                # do stuff
                return # end thread
            print item

撰写回答