【发布时间】:2011-06-14 14:24:16
【问题描述】:
我正在调查在具有 4G RAM 的 Ubuntu 机器上运行的 Python 应用程序的问题。该工具将用于审计服务器(我们更喜欢推出自己的工具)。它使用线程连接到大量服务器,并且许多 TCP 连接失败。但是,如果我在启动每个线程之间添加 1 秒的延迟,那么大多数连接都会成功。我已经使用这个简单的脚本来调查可能发生的事情:
#!/usr/bin/python
import sys
import socket
import threading
import time
class Scanner(threading.Thread):
def __init__(self, host, port):
threading.Thread.__init__(self)
self.host = host
self.port = port
self.status = ""
def run(self):
self.sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sk.settimeout(20)
try:
self.sk.connect((self.host, self.port))
except Exception, err:
self.status = str(err)
else:
self.status = "connected"
finally:
self.sk.close()
def get_hostnames_list(filename):
return open(filename).read().splitlines()
if (__name__ == "__main__"):
hostnames_file = sys.argv[1]
hosts_list = get_hostnames_list(hostnames_file)
threads = []
for host in hosts_list:
#time.sleep(1)
thread = Scanner(host, 443)
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
print "Host: ", thread.host, " : ", thread.status
如果我在 time.sleep(1) 注释掉的情况下运行此程序,例如 300 台主机,许多连接会因超时错误而失败,而如果我延迟一秒,它们不会超时。我是否在功能更强大的机器上运行的另一个 Linux 发行版上尝试了该应用程序并且没有那么多连接错误?是因为内核限制吗?我可以做些什么来让连接正常工作而不造成延迟?
更新
我还尝试了一个限制池中可用线程数的程序。通过将其减少到 20,我可以让所有连接正常工作,但它每秒只检查大约 1 个主机。因此,无论我尝试什么(进入睡眠(1)或限制并发线程的数量),我似乎都无法每秒检查超过 1 个主机。
更新
我刚刚发现了这个 question,看起来和我看到的很相似。
更新
我想知道使用 twisted 编写此内容是否有帮助?任何人都可以展示我的示例使用 twisted 编写的样子吗?
【问题讨论】:
-
您是否看到许多处于 TIME_WAIT 状态的连接 (
netstat)? stackoverflow.com/questions/410616/… -
在Python中使用线程时网络访问不是并发的,您需要使用多处理或类似gevent或eventlet的东西。查看 J.F. Sebastian 的回答
-
@cerberos:Python 通常会在执行 I/O 时释放 GIL,因此您可以使用线程,但您不应该创建数千个线程来连接数千个主机。
标签: python multithreading sockets