Python 到HTTP服务器的urllib.request连接的持久性
我想在我们的一台web服务器上做一些性能测试,看看服务器如何处理大量持久连接。不幸的是,我不太熟悉HTTP和web测试。以下是我迄今为止为此编写的Python代码:Python 到HTTP服务器的urllib.request连接的持久性,python,http,python-3.x,Python,Http,Python 3.x,我想在我们的一台web服务器上做一些性能测试,看看服务器如何处理大量持久连接。不幸的是,我不太熟悉HTTP和web测试。以下是我迄今为止为此编写的Python代码: import http.client import argparse import threading def make_http_connection(): conn = http.client.HTTPConnection(options.server, timeout=30) conn.connect()
import http.client
import argparse
import threading
def make_http_connection():
conn = http.client.HTTPConnection(options.server, timeout=30)
conn.connect()
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("num", type=int, help="Number of connections to make (integer)")
parser.add_argument("server", type=str, help="Server and port to connect to. Do not prepend \'http://\' for this")
options = parser.parse_args()
for n in range(options.num):
connThread = threading.Thread(target = make_http_connection, args = ())
connThread.daemon = True
connThread.start()
while True:
try:
pass
except KeyboardInterrupt:
break
我的主要问题是:如何保持这些连接?我设置了一个长超时,但这是一个非常粗糙的方法,我甚至不确定它是否会影响连接。只是偶尔请求一两个字节就行了吗
(另外,另一个不相关的注意事项是,是否有比丑陋的
等待键盘中断更好的过程,而True:
在我的代码末尾阻塞?我在这里有点超出了我的知识基础,但我假设当函数make_http_connection()完成时,您的线程将终止。)。也就是说,如果您想要它们,那么您需要包括:
while condition:
pass
在函数的末尾。我想你想让他们同时活跃起来?然后让函数修改一个全局变量,并使用条件根据options.num测试该值,以便进程在开始终止之前将等待所有进程运行
附带的问题是,猜猜你们的目标是什么,难道你们不能让线程来计算你们有多少个活动线程,并一直运行直到并没有剩余的线程吗
threading.active_count()
这里讨论的是阅读键盘,如果这是您需要的:
urllib.request
不支持持久连接。代码中有“连接:关闭”
硬编码。但是http.client
部分支持持久连接(包括旧式http/1.0保持活动状态
)。因此,问题的标题可能会产生误导
我想在我们的一台web服务器上做一些性能测试,看看服务器如何处理大量持久连接。不幸的是,我不太熟悉HTTP和web测试 您可以使用现有的http测试工具,例如httperf,而不是自己编写一个
我如何保持这些连接 要关闭http/1.1连接,客户端应明确指定
connection:close
头,否则服务器会认为该连接是持久的(尽管它可能会在任何时候关闭该连接,直到它尝试读取/写入该连接为止)
conn.connect()
几乎立即返回,线程结束。要强制每个线程保持与服务器的http连接,可以:
import time
def make_http_connection(*args, **kwargs):
while True: # make new http connections
h = http.client.HTTPConnection(*args, **kwargs)
while True: # make multiple requests using a single connection
try:
h.request('GET', '/') # send request; make conn. on the first run
response = h.getresponse()
while True: # read response slooowly
b = response.read(1) # read 1 byte
if not b:
break
time.sleep(60) # wait a minute before reading next byte
#note: the whole minute might pass before we notice that
# the server has closed the connection already
except Exception:
break # make new connection on any error
while threads:
try:
for t in threads[:]: # enumerate threads
t.join(.1) # timeout 0.1 seconds
if not t.is_alive():
threads.remove(t)
except KeyboardInterrupt:
break
注意:如果服务器返回“连接:关闭”
,则每个连接只有一个请求
(还有一点与此无关,等待键盘中断的过程是否比丑陋的while True:代码末尾的block更好?) 要等待所有线程完成或键盘中断发生,您可以:
import time
def make_http_connection(*args, **kwargs):
while True: # make new http connections
h = http.client.HTTPConnection(*args, **kwargs)
while True: # make multiple requests using a single connection
try:
h.request('GET', '/') # send request; make conn. on the first run
response = h.getresponse()
while True: # read response slooowly
b = response.read(1) # read 1 byte
if not b:
break
time.sleep(60) # wait a minute before reading next byte
#note: the whole minute might pass before we notice that
# the server has closed the connection already
except Exception:
break # make new connection on any error
while threads:
try:
for t in threads[:]: # enumerate threads
t.join(.1) # timeout 0.1 seconds
if not t.is_alive():
threads.remove(t)
except KeyboardInterrupt:
break
或者像这样:
while threading.active_count() > 1:
try:
main_thread = threading.current_thread()
for t in threading.enumerate(): # enumerate all alive threads
if t is not main_thread:
t.join(.1)
except KeyboardInterrupt:
break
由于各种原因,后者可能不起作用,例如,如果存在伪线程,例如在没有使用线程
模块的情况下在C扩展中启动的线程
提供比线程化
模块更高的抽象级别,并且可以隐藏一些复杂性
您可以在单个线程中同时打开多个连接,例如,直接使用requests.async
或gevent
。如果很多是真正的很多,那么您可能希望使用异步io而不是线程
+=
GRequests允许您将请求与Gevent一起使用,以轻松地生成异步HTTP请求
import grequests
urls = [
'http://www.heroku.com',
'http://tablib.org',
'http://httpbin.org',
'http://python-requests.org',
'http://kennethreitz.com'
]
requests = (grequests.get(u) for u in urls)
responses = grequests.map(requests)
请求持久的HTTP连接。您真的应该使用类似于此的基准测试工具。如果您没有使用HTTP的经验,尝试从头开始进行性能测试肯定会导致糟糕的结果。您所说的“持久连接”是什么意思?您的服务器的正常活动是客户端连接,服务器发送响应并关闭连接。@jjm特别指定使用“connection:Keep alive”头()保持活动的连接。此答案中包含了大量帮助。谢谢,J.F@Kudzu:我已经更新了这个问题,提到了
ThreadPoolExecutor
,请求。异步
提供了更高级别的接口。注意:“很多”可能会导致