Python线程中的死锁

Python线程中的死锁,python,multithreading,Python,Multithreading,我正在尝试用Python实现simpley portscanner。它通过创建多个工作线程来工作,这些线程扫描队列中提供的端口。它们将结果保存在另一个队列中。扫描所有端口时,线程和应用程序应终止。问题就在这里:对于少量的端口,一切正常,但如果我尝试扫描200个或更多端口,应用程序将陷入死锁。我不知道,为什么 class ConnectScan(threading.Thread): def __init__(self, to_scan, scanned): threadin

我正在尝试用Python实现simpley portscanner。它通过创建多个工作线程来工作,这些线程扫描队列中提供的端口。它们将结果保存在另一个队列中。扫描所有端口时,线程和应用程序应终止。问题就在这里:对于少量的端口,一切正常,但如果我尝试扫描200个或更多端口,应用程序将陷入死锁。我不知道,为什么

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没有被频繁调用。原因是,如果您尝试连接到过滤端口(即,您不会得到任何响应),套接字不会抛出异常,而是永远等待。那是我的僵局。