2014-07-21 134 views
5

我正在與python的HTTP通信的請求模塊,我想知道如何重用已建立的TCP連接?請求模塊是無狀態的,如果我反覆調用get來獲取相同的URL,它會不會每次都創建一個新的連接?python請求模塊和連接重用

謝謝!

+0

http://docs.python-requests.org/en/latest/user/advanced/#keep-alive – dm03514

回答

5

請求模塊是無狀態的,如果我反覆調用獲取相同的URL,它不會創建一個新的連接每次?

requests模塊不是無狀態的;它只是讓你忽略狀態,並有效地使用全球單身狀態,如果你選擇這樣做。*

而它(或者,而是其中一個底層庫,urllib3)維護一個連接池(主機名,端口)對,所以如果可能的話,它通常會神奇地重用連接。

由於the documentation說:

極好的消息 - 由於urllib3,保活是在一個會話中100%自動 !您在任何會話中發出的任何請求都會自動重複使用相應的連接!

請注意,一旦所有的主體數據都被讀取,連接只會被釋放回池以供重用 ;請確保將stream設置爲 False或者讀取Response對象的content屬性。

那麼,「如果可以」意味着什麼?正如上面的文檔所暗示的,如果你保持流式響應對象的活着,它們的連接顯然不能被重用。

此外,連接池確實是一個有限的緩存,而不是無限的,所以如果您的垃圾郵件了一噸的連接,其中兩個是在同一臺服務器,你不會總是重用的連接,只需通常是。但通常情況下,這就是你真正想要的。


*與此有關的特定狀態是transport adapter。每個會話都有一個傳輸適配器。您可以手動指定適配器,或者您可以指定全局默認值,或者您可以使用默認的全局默認值,它基本上只包含用於管理其HTTP連接的urllib3.PoolManager。有關更多信息,請閱讀文檔。

+1

非常感謝您的詳細回覆;這真的很有幫助。我還有一個問題。上述文檔中的「會話」是什麼?我通讀了文檔,實際上有一個Session對象。我通讀了「請求」代碼,併爲每個請求創建了一個Session對象。所以,如果連接只在Session中重用,那麼我不確定在兩個「get」調用之間連接將被重用。 – gmemon

+0

@gmemon:對不起,這是不好的措辭。我的意思是構成全局狀態的適配器的集合,在這種情況下,特別是'HTTPAdapter'(這是持有'urllib3.PoolManager'的東西)。我不知道這是對的,但「會議」顯然是一個不錯的選擇。我會編輯答案。感謝您指出了這一點。 – abarnert

18

全局函數如requests.getrequests.post在每次調用時創建requests.Session實例。用這個函數進行的連接不能被重用,因爲你不能訪問自動創建的會話並將它的連接池用於後續請求。如果你只需要做幾個請求,就可以使用這個函數。否則,你會想自己管理會話。

以下是使用全局函數和會話時requests行爲的快速顯示。

準備,沒有真正的問題有關:

>>> _ = requests.get("https://www.wikipedia.org") 
Starting new HTTPS connection (1): www.wikipedia.org 
>>> _ = requests.get("https://www.wikipedia.org") 
Starting new HTTPS connection (1): www.wikipedia.org 

但是如果你使用同一個會話的後續調用,新:

>>> import logging, requests, timeit 
>>> logging.basicConfig(level=logging.INFO, format="%(message)s") 

見,新的連接在每次調用get時間確定不會爲每個請求創建連接:

>>> session = requests.Session() 
>>> _ = session.get("https://www.wikipedia.org") 
Starting new HTTPS connection (1): www.wikipedia.org 
>>> _ = session.get("https://www.wikipedia.org") 
>>> _ = session.get("https://www.wikipedia.org") 
>>> _ = session.get("https://www.wikipedia.org") 

性能:

>>> timeit.timeit('_ = requests.get("https://www.wikipedia.org")', 'import requests', number=100) 
Starting new HTTPS connection (1): www.wikipedia.org 
Starting new HTTPS connection (1): www.wikipedia.org 
Starting new HTTPS connection (1): www.wikipedia.org 
... 
Starting new HTTPS connection (1): www.wikipedia.org 
Starting new HTTPS connection (1): www.wikipedia.org 
Starting new HTTPS connection (1): www.wikipedia.org 
52.74904417991638 
>>> timeit.timeit('_ = session.get("https://www.wikipedia.org")', 'import requests; session = requests.Session()', number=100) 
Starting new HTTPS connection (1): www.wikipedia.org 
15.770191192626953 
當你重用會話(從而會話的連接池)

工程快得多。