Python线程中的死锁
我正在尝试用Python实现simpley portscanner。它通过创建多个工作线程来工作,这些线程扫描队列中提供的端口。它们将结果保存在另一个队列中。扫描所有端口时,线程和应用程序应终止。问题就在这里:对于少量的端口,一切正常,但如果我尝试扫描200个或更多端口,应用程序将陷入死锁。我不知道,为什么Python线程中的死锁,python,multithreading,Python,Multithreading,我正在尝试用Python实现simpley portscanner。它通过创建多个工作线程来工作,这些线程扫描队列中提供的端口。它们将结果保存在另一个队列中。扫描所有端口时,线程和应用程序应终止。问题就在这里:对于少量的端口,一切正常,但如果我尝试扫描200个或更多端口,应用程序将陷入死锁。我不知道,为什么 class ConnectScan(threading.Thread): def __init__(self, to_scan, scanned): threadin
class ConnectScan(threading.Thread):
def __init__(self, to_scan, scanned):
threading.Thread.__init__(self)
self.to_scan = to_scan
self.scanned = scanned
def run(self):
while True:
try:
host, port = self.to_scan.get()
except Queue.Empty:
break
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((host, port))
s.close()
self.scanned.put((host, port, 'open'))
except socket.error:
self.scanned.put((host, port, 'closed'))
self.to_scan.task_done()
class ConnectScanner(object):
def scan(self, host, port_from, port_to):
to_scan = Queue.Queue()
scanned = Queue.Queue()
for port in range(port_from, port_to + 1):
to_scan.put((host, port))
for i in range(20):
ConnectScan(to_scan, scanned).start()
to_scan.join()
有人知道可能出了什么问题吗?另外,我也希望您能提供一些关于如何在Python中调试此类线程问题的技巧。我看不出您的代码有任何明显的错误,但就目前情况而言,中断将永远不会发生-
self。to_scan.get()
将永远等待,而不是引发Queue.Empty。假设您在启动线程之前正在加载带有要扫描的端口的队列,那么您可以将其更改为self.to_scan.get(False)
,以便在所有端口都已声明时让工作线程正确退出
再加上您有非守护进程线程(在主线程完成后将使进程保持活动状态的线程),这可能是挂起的原因。尝试在之后打印一些内容,以便\u scan.join()
查看它是在此处停止,还是在进程退出时停止
正如Ray所说,如果在self.to\u scan.get()
和self.to\u scan.task\u done()
之间引发了socket.error以外的异常,则join
调用将挂起。将该代码更改为使用try/finally以确保:
def run(self):
while True:
try:
host, port = self.to_scan.get(False)
except Queue.Empty:
break
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((host, port))
s.close()
self.scanned.put((host, port, 'open'))
except socket.error:
self.scanned.put((host, port, 'closed'))
finally:
self.to_scan.task_done()
通常,调试多线程进程是很棘手的。我尽量避免任何无限期的阻塞——最好让某个东西因为超时时间太短而大声崩溃,而不是让它永远停止等待一个永远不会出现的项目。因此,我要为您的self.to_scan.get
、socket.connect
和to_scan.join
调用指定超时
使用logging
计算事件发生的顺序-打印可以从不同的线程进行交错,但记录器是线程安全的
此外,类似这样的东西可以方便地转储每个线程的当前堆栈跟踪
我没有使用任何支持在Python中调试多个线程的调试器,但列出了一些调试器。很可能没有使用to_扫描队列上的所有项目,并且您调用task_done方法的次数不足,无法取消阻止ConnectScanner
是否在ConnectScan.run运行时引发了一个异常,而您没有捕获该异常,并且线程过早终止?感谢您的提示。他们帮助我找到了解决方案,尽管它不是抛出的异常,而是未抛出的异常。我会看看你建议的调试技术。你是对的,tast_done没有被频繁调用。原因是,如果您尝试连接到过滤端口(即,您不会得到任何响应),套接字不会抛出异常,而是永远等待。那是我的僵局。