簡體   English   中英

urllib.request連接到HTTP服務器的持久性

[英]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.asyncgevent ,而不是每個連接的線程模型。

如果有很多真的很多 ,那么你可能想使用異步IO不線程。

requests + gevent = grequests

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM