You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Greenlet数量会影响HTTP请求的响应耗时?

Hey Roger, let's break down why you're seeing slower response times as concurrency ramps up with gevent, and walk through fixes to get better performance:

1. Requests Default Connection Pool Limits Are Holding You Back

The requests library uses a default HTTPAdapter with a max connection pool size of 10 (pool_connections=10, pool_maxsize=10). That means even if you spawn 100 gevent coroutines, only 10 can actually establish a connection to your target server at once. The other 90 will sit idle waiting for connections to free up, which directly inflates your response times.

Fix it by expanding the connection pool:

import gevent
from gevent import monkey
import requests
from requests.adapters import HTTPAdapter

# Patch first - critical to do this before importing other network-related modules
monkey.patch_all(thread=False)

# Create a session with an expanded connection pool
session = requests.Session()
# Match your concurrency level with pool size (adjust based on testing)
adapter = HTTPAdapter(pool_connections=100, pool_maxsize=100)
session.mount("https://", adapter)
session.mount("http://", adapter)

def action():
    resp = session.get("https://www.google.com")
    if resp.status_code == 200:
        print(resp.elapsed.total_seconds())

jobs = [gevent.spawn(action) for _ in range(100)]
gevent.joinall(jobs)
2. Target Server Throttling/Resource Limits

When you hit a server with 100 concurrent requests, it’s likely to trigger rate limiting, queueing, or resource exhaustion on the server side. Services like Google actively manage request load from single IPs, so your requests might be delayed intentionally to prevent abuse.

Mitigate this with controlled concurrency:

  • Use gevent.Pool to cap concurrent requests at a server-friendly level (test to find the sweet spot):
with gevent.Pool(30) as pool:
    # Map the action function to 100 tasks, capped at 30 concurrent
    pool.map(lambda _: action(), range(100))
  • Add gentle retry logic for timeouts or 5xx errors (avoid aggressive retries that worsen the problem):
from requests.exceptions import RequestException
import time

def action():
    retries = 3
    for attempt in range(retries):
        try:
            resp = session.get("https://www.google.com", timeout=5)
            if resp.status_code == 200:
                print(resp.elapsed.total_seconds())
            break
        except RequestException:
            if attempt < retries - 1:
                time.sleep(0.5)
            else:
                print("Request failed after retries")
3. Monkey Patch Order & Configuration

You’re already patching before importing requests (good!), but double-check:

  • monkey.patch_all(thread=False) disables thread-related patches, which is fine for requests since it uses sockets, but ensure no network-related modules are imported before patching. If any module initializes sockets pre-patch, coroutine switching won’t work as expected, leading to blocking waits.
  • For DNS bottlenecks (common in high concurrency), enable asynchronous DNS patching:
monkey.patch_all(thread=False, dns=True)
4. Bonus: Use More Efficient HTTP Clients

If you really want to squeeze out performance, consider switching to httpx—it supports HTTP/2 multiplexing (which lets multiple requests share a single connection) and plays nicely with gevent. Here’s a quick example:

import httpx
from gevent import monkey, spawn, joinall

monkey.patch_all(thread=False)

client = httpx.Client(http2=True)

def action():
    resp = client.get("https://www.google.com")
    if resp.status_code == 200:
        print(resp.elapsed.total_seconds())

jobs = [spawn(action) for _ in range(100)]
joinall(jobs)

内容的提问来源于stack exchange,提问作者Roger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:47:50