コネクションプールなしでhttpxを使う場合の高速化

httpx をコネクションプールありで使う場合は client = httpx.Client() して client.get() などを使いますが、コネクションプールなしで使う場合は httpx.get() などを使います。

この httpx.get() のような単発でHTTPリクエストを実行するAPIは実際には内部で httpx.Client()インスタンスを生成して破棄しています。実はこの Client()インスタンス生成が遅いのです。

# x1.py
from httpx import Client
for _ in range(100):
    c = Client()
$ hyperfine '.venv/bin/python x1.py'
Benchmark 1: .venv/bin/python x1.py
  Time (mean ± σ):      1.484 s ±  0.018 s    [User: 1.421 s, System: 0.041 s]
  Range (min … max):    1.455 s …  1.522 s    10 runs

100回クライアントを作るのに1.5秒かかっています。1回あたり15msです。もうちょっとなんとかしたい。

実はこのクライアントの生成時間のほとんどは、SSLContext()を作るのに使われています。コネクションプールを使わない場合もSSLContextだけを使い回すことでhttpxを高速化できます。

from httpx import Client, create_ssl_context
ssl_context = create_ssl_context()
for _ in range(100):
    c = Client(verify=ssl_context)
$ hyperfine '.venv/bin/python x1.py' '.venv/bin/python x2.py'
Benchmark 1: .venv/bin/python x1.py
  Time (mean ± σ):      1.477 s ±  0.024 s    [User: 1.412 s, System: 0.040 s]
  Range (min … max):    1.453 s …  1.532 s    10 runs

Benchmark 2: .venv/bin/python x2.py
  Time (mean ± σ):     120.7 ms ±   5.3 ms    [User: 85.6 ms, System: 15.2 ms]
  Range (min … max):   104.2 ms … 129.6 ms    22 runs

Summary
  .venv/bin/python x2.py ran
   12.23 ± 0.58 times faster than .venv/bin/python x1.py

10倍以上高速化できました。

実際に使う場合には get() などのメソッドが verify キーワード引数を受け取るのでそこに SSLContext を渡します。

import httpx

ssl_context = httpx.create_ssl_context()
res = httpx.get('https://google.com', verify=ssl_context)
print("Status:", res.status_code)
print(res.text[:100])
このブログに乗せているコードは引用を除き CC0 1.0 で提供します。