创建工作者池并不会把已下载的页面交给调用方。请保留并消费所提交工作返回的值:

from concurrent.futures import ThreadPoolExecutor
import urllib3

manager = urllib3.ProxyManager(
    'http://proxy.example:8080',
    maxsize=4,
    block=True,
)

def fetch(url):
    response = manager.request(
        'GET', url, timeout=urllib3.Timeout(connect=5, read=15),
    )
    return url, response.status, response.data

try:
    with ThreadPoolExecutor(max_workers=4) as workers:
        results = list(workers.map(fetch, urls))
finally:
    manager.clear()

这段代码假设 URL 列表有限且响应大小正常。对于允许的、无需代理认证的公开 URL 检查,可以用 HTTP 代理列表 中的候选项替换管理器里的示例 HTTP 端点。每个结果都包含其 URL,因此调用方可以把状态和响应体与正确的请求关联起来。map 按输入顺序返回结果;工作线程中的异常会在取回该结果时抛出。

已配置的 ProxyManager 拥有这些请求的连接池。使用这里默认的预加载响应模式时,urllib3 会读取响应体并把连接归还到池中。流式版本则需要显式消费并释放连接。

maxsize 通常控制保留的可复用连接数,而不是对每个已打开套接字的硬性上限。block=True 会改变相关连接池的行为,使调用方等待空闲连接,而不是在该池上限之外继续新开连接。

在这个示例中,工作者数量限制了并发调用。目的地很多时,连接池布局以及 HTTPS 隧道所使用的路由也很重要;不应把单个连接池的设置描述成适用于每台主机的全局套接字配额。

相关文章