我有一个这样定义的线程类:
#!/usr/bin/python
import threading
import subprocess
class PingThread (threading.Thread):
ipstatus = ''
def __init__(self, ip):
threading.Thread.__init__(self)
self.ipaddress = ip
def ping(self, ip):
print 'Pinging ' + ip + '...'
ping_response = subprocess.Popen(["ping", "-c", "1", ip], stdout=subprocess.PIPE).stdout.read()
if '100.0% packet loss' not in str(ping_response):
return True
return False
def set_ip_status(self, status):
self.ipstatus = status
def get_ip_status(self):
return self.ipstatus
def run(self):
self.ipaddress = self.ipaddress.strip('\n\t')
pingResponse = self.ping(self.ipaddress)
if pingResponse:
self.set_ip_status(self.ipaddress + ' is up!')
else:
self.set_ip_status(self.ipaddress + ' is down!')
我正在浏览一个ip地址列表并将其发送到PingThread
并让此类ping ip地址。当这些线程全部完成后,我希望它通过调用get_ip_status()
来获取每个线程的状态。我的代码中有q.join()
,应该等到队列中的所有项都完成(根据我的理解,如果我错了,请更正我,还是线程新手)但我的代码永远不会通过{ {1}}。我测试了并且所有线程都完成了,并且所有IP地址都被ping了,但是q.join
没有意识到这一点。为什么是这样?我究竟做错了什么?我正在创建这样的线程:
q.join()
答案 0 :(得分:3)
你误解了Queue.join
的工作原理。 Queue.join
旨在与Queue.task_done
一起使用;在制作人端,您put
项目的一端是Queue
,然后拨打Queue.join
等待处理您put
的所有项目。然后在消费者端,get
Queue
中的Queue.task_done
项,处理它,然后在完成后调用task_done
。在put
Queue
中Queue.join
的所有项目调用Queue
后,join
将取消阻止。
但你不是那样做的。您只需启动一堆线程,将它们添加到task_done
,然后在其上调用Queue.get
。您根本没有使用Queue.join
,而您只是在Queue
之后调用Thread
,看起来您只是在用它们来获取线程对象之后完成。但这并不是真的如何运作; Queue.join
不知道其中有Thread
个对象,只需调用join
就不会等待其中的threads = []
for ip in trainips:
thread = PingThread(ip)
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
print thread.get_ip_status()
个对象完成。
实际上,看起来您需要做的就是将线程放在列表中,然后在每个线程上调用{{1}}。
{{1}}
答案 1 :(得分:2)
正如文档所说,Queue.join
阻止,直到队列中的所有项目都被获取并处理完毕。
但是你不是每次都试图获取这些项目,直到之后 join
(即便如此,你也不会标记它们被处理过)。
所以,在你完成join
循环之前,你无法超越while
,在你超越join
之前你无法进入,所以你永远阻止
要使join
工作,您必须将最后三行改为:
while not q.empty():
print q.get().get_ip_status()
q.task_done()
q.join()
然而,一个更简单的解决方案就是不要join
队列。相反,你可以 join
所有线程;然后你知道get
所有值都是安全的。但请注意,如果你这样做,队列就没有理由成为Queue
;它可以只是一个普通的list
。此时你已经有效地获得了dano's answer。
或者,您可以更改代码以实际使用队列。而不是将线程放入队列中,将队列传递给线程函数,并将其结果放在队列中,而不是将其存储为属性。然后,你可以在你正在做的时候循环get()
,它会自动处理你需要的所有阻塞。文档中Queue.join
的示例显示了如何完成您想要做的事情。
后一种解决方案的优点是你不再需要你的任务和线程一对一地映射 - 例如,使用一个包含16个线程的池来运行128个任务,你仍然会得到128个队列上的值。 *
*但是如果你想这样做,你可能会使用multiprocessing.dummy.Pool
或(来自PyPI上的concurrent.futures
后端)futures.ThreadPoolExecutor
而不是自己构建它。 /子>