[英]Persistence of urllib.request connections to a HTTP server
我想在我們的一個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()
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
我的主要問題是: 如何保持這些連接存活? 我設置了一個很長的超時,但這是一個非常粗糙的方法,我甚至不確定它會影響連接。 只需要每隔一段時間請一個字節或兩個字節嗎?
(另外,在一個不相關的說明中,是否有一個更好的程序等待鍵盤中斷而不是丑陋while True:
阻塞在我的代碼末尾?)
urllib.request
不支持持久連接。 代碼中有'Connection: close'
硬編碼。 但http.client
部分支持持久連接(包括遺留的http / 1.0 keep-alive
)。 所以問題標題可能會產生誤導。
我想在我們的一個Web服務器上進行一些性能測試,以查看服務器如何處理大量持久連接。 不幸的是,我對HTTP和Web測試並不十分熟悉。
您可以使用現有的http測試工具,例如slowloris ,httperf,而不是自己編寫。
如何保持這些連接存活?
要關閉http / 1.1連接,客戶端應該顯式指定Connection: close
頭,否則服務器認為連接是持久的(雖然它可能隨時關閉它, http.client
在嘗試讀/寫之前不會知道它到連接)。
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
注意:如果服務器返回'Connection: close'
則每個連接只有一個請求。
(另外,在一個不相關的說明中,是否有一個更好的程序等待鍵盤中斷而不是丑陋而True:阻塞在我的代碼末尾?)
要等到所有線程完成或發生KeyboardInterrupt
,您可以:
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
后者可能由於各種原因而無法工作,例如,如果存在虛擬線程,例如在不使用threading
模塊的情況下在C擴展中啟動的threading
。
concurrent.futures.ThreadPoolExecutor提供了比threading
模塊更高的抽象級別,它可以隱藏一些復雜性。
您可以在單個線程中同時打開多個連接,而gevent
直接使用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連接。
你真的應該使用像Funkload這樣的基准工具來做到這一點。 如果您沒有使用HTTP的經驗,那么嘗試從頭開始進行性能測試肯定會導致不良結果。
我在這里的知識庫之外會有點偏差,但我會假設你的線程在函數make_http_connection()完成時完成。 那就是如果你想要它們,你想要包括:
while condition:
pass
在功能結束時。 我想你們希望他們同時變得活躍起來? 然后讓函數修改一個全局變量並使用條件對options.num測試該值,以便進程在它們開始終止之前等待所有進程運行。
側面問題,猜測你的目標是什么,你不能只是要求線程計算你有多少活線程並繼續運行直到沒有剩下?
threading.active_count()
這里討論了閱讀鍵盤,如果這是你需要的:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.