从并发的 urllib3 代理请求中收集每个结果
在工作线程之间共享已配置的 ProxyManager,消费执行器的结果迭代器,并区分连接池保留与连接上限。
创建工作者池并不会把已下载的页面交给调用方。请保留并消费所提交工作返回的值:
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 隧道所使用的路由也很重要;不应把单个连接池的设置描述成适用于每台主机的全局套接字配额。