我遇到一些问题,太多线程尚未完成。 我认为队列命令.join()只是关闭队列而不是使用它的线程。
在我的脚本中,我需要检查280k域,并为每个域获取他的MX记录列表,并获取服务器的IPv6地址(如果有)。
我使用了线程,并感谢他们脚本的速度快了很多倍。但是有一个问题,虽然队列中有join(),但活动线程的数量一直在增长,直到发生错误,通知无法创建任何新线程(OS的限制?)。
当我从数据库中检索新域时,如何在每个For循环后终止/关闭/停止/重置线程?
线程类定义......
class MX_getAAAA_thread(threading.Thread):
def __init__(self,queue,id_domain):
threading.Thread.__init__(self)
self.queue = queue
self.id_domain = id_domain
def run(self):
while True:
self.mx = self.queue.get()
res = dns.resolver.Resolver()
res.lifetime = 1.5
res.timeout = 0.5
try:
answers = res.query(self.mx,'AAAA')
ip_mx = str(answers[0])
except:
ip_mx = "N/A"
lock.acquire()
sql = "INSERT INTO mx (id_domain,mx,ip_mx) VALUES (" + str(id_domain) + ",'" + str(self.mx) + "','" + str(ip_mx) + "')"
try:
cursor.execute(sql)
db.commit()
except:
db.rollback()
print "MX" , '>>' , ip_mx, ' :: ', str(self.mx)
lock.release()
self.queue.task_done()
正在使用的线程类...... (主要的For循环不在这里,这只是他身体的一部分)
try:
answers = resolver.query(domain, 'MX')
qMX = Queue.Queue()
for i in range(len(answers)):
t = MX_getAAAA_thread(qMX,id_domain)
t.setDaemon(True)
threads.append(t)
t.start()
for mx in answers:
qMX.put(mx.exchange)
qMX.join()
except NoAnswer as e:
print "MX - Error: No Answer"
except Timeout as etime:
print "MX - Error: dns.exception.Timeout"
print "end of script"
我试图:
for thread in threads:
thread.join()
在队列完成之后,但是thread.join()永远不会停止等待,尽管事实上没有必要等待,因为当queue.join()执行时,线程无关。
答案 0 :(得分:5)
当我的线程涉及这样的无限循环时,我经常做的是将条件改为我可以从外部控制的东西。例如:
def run(self):
self.keepRunning = True
while self.keepRunning:
# do stuff
这样,我可以从外部更改keepRunning
属性并将其设置为false,以便在下次检查循环条件时正常终止该线程。
顺便说一下。因为你似乎为你放入队列的每个项目只生成一个线程,你甚至根本不需要让线程循环,尽管我认为你应该总是强制执行可以创建的线程的最大限制这样(即for i in range(min(len(answers), MAX_THREAD_COUNT)):
)
在您的情况下,您可以只重用线程,而不是在每个for循环迭代中终止线程。从我从线程的源代码中收集到的内容,所有使迭代独有的线程都是您在创建时设置的id_domain
属性。然而,你可以只提供你的队列,所以线程是完全独立的,你可以重用它们。
这可能是这样的:
qMX = Queue.Queue()
threads = []
for i in range(MAX_THREAD_COUNT):
t = MX_getAAAA_thread(qMX)
t.daemon = True
threads.append(t)
t.start()
for id_domain in enumerateIdDomains():
answers = resolver.query(id_domain, 'MX')
for mx in answers:
qMX.put((id_domain, mx.exchange)) # insert a tuple
qMX.join()
for thread in threads:
thread.keepRunning = False
当然,你需要稍微改变你的线程:
class MX_getAAAA_thread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
self.keepRunning = True
while self.keepRunning:
id_domain, mx = self.queue.get()
# do stuff
答案 1 :(得分:4)
我不明白为什么你首先需要Queue
毕竟在你的设计中,每个线程只处理一个任务
您应该能够在创建时将该任务传递给线程
这样你就不需要Queue
而且你摆脱了while
- 循环:
class MX_getAAAA_thread(threading.Thread):
def __init__(self, id_domain, mx):
threading.Thread.__init__(self)
self.id_domain = id_domain
self.mx = mx
然后你可以摆脱while
- 方法中的run
- 循环:
def run(self):
res = dns.resolver.Resolver()
res.lifetime = 1.5
res.timeout = 0.5
try:
answers = res.query(self.mx,'AAAA')
ip_mx = str(answers[0])
except:
ip_mx = "N/A"
with lock:
sql = "INSERT INTO mx (id_domain,mx,ip_mx) VALUES (" + str(id_domain) + ",'" + str(self.mx) + "','" + str(ip_mx) + "')"
try:
cursor.execute(sql)
db.commit()
except:
db.rollback()
print "MX" , '>>' , ip_mx, ' :: ', str(self.mx)
为每个任务创建一个线程
for mx in answers:
t = MX_getAAAA_thread(qMX, id_domain, mx)
t.setDaemon(True)
threads.append(t)
t.start()
加入他们
for thread in threads:
thread.join()
答案 2 :(得分:2)
加入线程会起到作用,但是你的情况下的连接是无限期阻塞的,因为你的线程永远不会退出你的运行循环。您需要退出run方法,以便可以连接线程。