web-dev-qa-db-ja.com

pythonリクエストモジュールと接続の再利用

私はHTTP通信用のpythonのリクエストモジュールを使用していて、すでに確立されているTCP接続を再利用する方法を知りたいですか?リクエストモジュールはステートレスであり、同じURLに対してgetを繰り返し呼び出すと、毎回新しい接続を作成しませんか?

ありがとう!!

20
gmemon

要求モジュールはステートレスであり、同じURLに対してgetを繰り返し呼び出した場合、毎回新しい接続が作成されないのですか?

requestsモジュールはステートレスではありません。状態を無視し、必要に応じてグローバルシングルトン状態を効果的に使用できるようにします。*

そして、それ(または、むしろ、基礎となるライブラリの1つであるurllib3)は、(ホスト名、ポート)のペアによってキー設定された接続プールを維持するため、通常、接続を魔法のように再利用できます。

ドキュメント が言うように:

すばらしいニュース— urllib3のおかげで、キープアライブはセッション内で100%自動です。セッション内で行ったリクエストは、適切な接続を自動的に再利用します!

すべての本文データが読み取られた後、接続は解放されて再利用のためにプールに戻されることに注意してください。必ずstreamFalseに設定するか、contentオブジェクトのResponseプロパティを読み取ってください。

では、「可能であれば」とはどういう意味ですか?上記のドキュメントが示すように、ストリーミング応答オブジェクトを存続させている場合、それらの接続は明らかに再利用できません。

また、接続プールは実際には無限ではなく有限のキャッシュであるため、大量の接続をスパム送信し、そのうちの2つが同じサーバーに対するものである場合は、常にしません頻繁に接続を再利用します。しかし、通常、それが実際に必要なことです。


*ここで関連する特定の状態は トランスポートアダプター です。各セッションはトランスポートアダプターを取得します。アダプタを手動で指定することも、グローバルデフォルトを指定することも、デフォルトのグローバルデフォルトを使用することもできます。これは、基本的にHTTP接続を管理するためのurllib3.PoolManagerをラップするだけです。詳細については、ドキュメントをご覧ください。

5
abarnert

requests.getrequests.postなどのグローバル関数は、各呼び出しでrequests.Sessionインスタンスを作成します。これらの関数で作成された接続は再利用できません。自動作成されたセッションにアクセスして、その後のリクエストでその接続プールを使用することができないためです。ほんの少しのリクエストを行う必要がある場合は、これらの関数を使用しても問題ありません。それ以外の場合は、自分でセッションを管理する必要があります。

以下は、グローバルrequests関数とセッションを使用した場合のgetの動作の簡単な表示です。

準備、質問にはあまり関係ありません:

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

getを呼び出すたびに新しい接続が確立されます。

>>> _ = 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

ただし、後続の呼び出しに同じセッションを使用すると、接続は再利用されます。

>>> 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

セッション(したがってセッションの接続プール)を再利用すると、はるかに高速に動作します。

49
Dmytro Kyrychuk