在python线程队列中调用类方法

时间:2017-08-01 07:52:53

标签: python multithreading class

有人可以详细说明为什么这个线程代码可以调用一个类'方法永远不会完成?

from Queue import Queue
from threading import Thread

class SimpleThing(object):
    def __init__(self, name):
        self.name = name

    def print_name(self):
        print self.name

class ThingSpawner(object):
    def __init__(self, name_list):
        self.things  = [SimpleThing(name) for name in name_list]
        self.thread_queue = Queue()

    def run(self):
        for thing in self.things:
            t = Thread(target=thing.print_name, name=thing.name)
            t.daemon = True
            t.start()
            self.thread_queue.put(t)
        self.thread_queue.join()

thing_list = ['cat', 'dog', 'llama', 'bat']

sp = ThingSpawner(thing_list)
sp.run()

代码将清楚地运行print_name方法,但不会join()并退出。

此外,修改此代码以使join()完成的最佳方法是什么?其动机是将一个现有的python控件类用于一些硬件,并允许您并行调用控件类的(非常慢)方法。谢谢!

2 个答案:

答案 0 :(得分:1)

当你做的时候

self.thread_queue.put(t)

显然,您正在为Queue添加一些线程。但是,我不确定为什么。你永远不会再使用那个队列来做任何事情,而且完全没必要。更糟糕的是,你打电话给

self.thread_queue.join()

这基本上等待队列清空,永远不会发生,因为你永远不会清空它或对它做任何事情。

如果我复制粘贴所有代码,但根本没有任何Queue,那么一切都很好......

from threading import Thread

class SimpleThing(object):
    def __init__(self, name):
        self.name = name

    def print_name(self):
        print self.name

class ThingSpawner(object):
    def __init__(self, name_list):
        self.things  = [SimpleThing(name) for name in name_list]

    def run(self):
        for thing in self.things:
            t = Thread(target=thing.print_name, name=thing.name)
            t.daemon = True
            t.start()

thing_list = ['cat', 'dog', 'llama', 'bat']

sp = ThingSpawner(thing_list)
sp.run()

然而,这不是你想要的!因为你的线程是守护进程,所以当主程序退出时它们将退出,即使它们尚未完成(如果我在打印名称之前添加了sleep(1)之类的延迟)。如果要等待它们完成,您应该在线程上调用join(),而不是队列。所以我们首先返回线程:

    def run(self):
        all_threads = []
        for thing in self.things:
            t = Thread(target=thing.print_name, name=thing.name)
            t.daemon = True
            t.start()
            all_threads.append(t)
        return all_threads

当我们run时,我们会这样做:

threads = sp.run()
for t in threads:
    t.join()

答案 1 :(得分:0)

感谢Ofer提供了我刚才接受的明确答案 - 我确实没有正确使用队列!现在你已经重新认识了队列,你已经指出了我的错误,为了繁荣,这是使用队列的另一种方法:

from Queue import Queue
from threading import Thread

class SimpleThing(object):
    def __init__(self, name, q):
        self.name = name

    def print_name(self, q):
        print self.name
        q.get()
        q.task_done()

class ThingSpawner(object):
    def __init__(self, name_list):
        self.thread_queue = Queue()
        self.things  = [SimpleThing(name, self.thread_queue) for name in name_list]


    def run(self):
        for thing in self.things:
            t = Thread(target=thing.print_name, name=thing.name, args=(self.thread_queue,))
            t.daemon = True
            t.start()
            self.thread_queue.put(t)
        self.thread_queue.join()

thing_list = ['cat', 'dog', 'llama', 'bat']

sp = ThingSpawner(thing_list)
sp.run()
一旦我理解了我的错误,

This tutorial对线程和队列很有用。