Python 代理检查:为什么 Future.cancel() 会让线程继续运行
理解为什么取消待处理的 future 并不能停止正在进行的网络检查,并在不声称能证明目标健康的前提下限制代理竞速。
一个 worker 找到了可用的代理。你返回它的地址,对其它 future 调用 cancel,并期望网络活动停止。它可能并不会停止。
Future 可以在其 callable 开始之前被取消。一旦线程已经在执行请求,取消它的 Future 并不能中断该 socket 操作。worker 需要自己的有界网络操作和清理路径。
executor 的生命周期同样重要。离开 ThreadPoolExecutor 上下文会等待其工作完成。找到一个快速结果后还要等若干个慢 worker,会让调用方的总延迟看起来完全不像获胜者报告的延迟。
在开始之前限制竞速
- 限制同时检查的数量,而不是提交一份无界的公开列表。免费代理列表为检查器的输入提供候选,同时为 worker 保留每个端点的协议。
- 为每个请求设置合适的连接与读取策略。
- 为调用方设置整体决策预算。
- 明确由谁排空或关闭那些比决策活得更久的 worker 的结果。
更少地等待 Future 并不等于让它底层的请求更短。同样,放弃结果并不会立即释放所有网络资源。
第一个成功结果也只是第一次成功的检查。它可能取决于调度、缓存的连接以及具体的检查目标。它不能证明该端点是全局最快的,也不能证明真实任务会成功。
通常,一个保留近期观测的小型池,比在每次下载前对整张列表竞速要简单。用真实操作的结果更新记录,并配合受控的故障恢复策略。预检应当挣回它的成本,而不是出于习惯把每项任务都翻倍。