多线程爬虫与流式并发:平缓预热设计实战
多线程爬虫与流式并发:平缓预热设计实战
多线程爬虫 / 批量接口查询:平缓预热(Warm-up)+ 流式并发 设计实战
这篇专门讲核心重点:平缓预热多线程架构,带完整可复用代码,教你如何实现无峰值、压力均匀、高效稳定的批量并发请求。
一、核心设计:什么是「平缓预热 + 流式并发」?
普通多线程:一次性把所有任务扔进线程池 → 瞬间爆发大量请求 → 被封 IP、接口报错、服务崩溃。
平缓预热架构(本文重点):
-
预热阶段:逐个启动线程,等上一个真正开始请求了,再启动下一个 → 无请求峰值
-
运行阶段:完成一个,补充一个 → 始终保持固定并发数 → 压力全程均匀
-
优势:效率最高、对接口最友好、适合万级以上大数据量
二、完整可复用核心代码(Python)
直接复制可用,这是平缓预热多线程的标准模板:
import threading
import time
from concurrent.futures import ThreadPoolExecutor
# ======================
# 【核心】平缓预热 + 流式并发控制器
# ======================
class WarmUpExecutor:
def __init__(self, max_workers: int, delay: float = 1.0):
self.executor = ThreadPoolExecutor(max_workers=max_workers)
self.max_workers = max_workers
self.delay = delay # 预热间隔
self.futures = []
self.lock = threading.Lock()
def submit_warm_up(self, task_fn, *args):
"""平缓预热提交任务:逐个启动,避免瞬间并发"""
future = self.executor.submit(task_fn, *args)
# 预热阶段:等待一小段时间再提交下一个
if len(self.futures) < self.max_workers:
time.sleep(self.delay)
self.futures.append(future)
return future
def submit_stream(self, task_fn, *args):
"""正常流式提交:完成一个补一个"""
return self.executor.submit(task_fn, *args)
# ======================
# 你的业务请求函数
# ======================
def query_company(name: str):
"""替换成你的接口查询逻辑"""
print(f"[查询中] {name}")
time.sleep(2) # 模拟请求耗时
return f"查询结果:{name}"
# ======================
# 使用示例
# ======================
if __name__ == "__main__":
# 配置
MAX_WORKERS = 3 # 最大并发
DELAY = 1.0 # 预热间隔(秒)
company_list = [f"公司{i}" for i in range(20)]
# 初始化控制器
executor = WarmUpExecutor(max_workers=MAX_WORKERS, delay=DELAY)
result_list = []
print("=== 开始平缓预热启动 ===")
# 1. 平缓预热启动
for name in company_list[:MAX_WORKERS]:
executor.submit_warm_up(query_company, name)
print("\n=== 进入稳态流式运行 ===")
# 2. 流式补充任务
for name in company_list[MAX_WORKERS:]:
# 完成一个任务,立即提交一个
done_futures = [f for f in executor.futures if f.done()]
for f in done_futures:
executor.futures.remove(f)
result_list.append(f.result())
# 提交新任务
executor.submit_stream(query_company, name)
# 等待所有任务结束
executor.executor.shutdown()
print("\n=== 全部完成 ===")
三、重点讲解:平缓预热到底做了什么?
1. 预热阶段(关键)
if len(self.futures) < self.max_workers:
time.sleep(self.delay)
-
前 N 个任务(N = 并发数)逐个提交
-
每提交一个,等待
delay秒再提交下一个 -
效果:请求从 0 → 1 → 2 → 3 平稳上升,无瞬间峰值
2. 运行阶段(流式并发)
done_futures = [f for f in executor.futures if f.done()]
for f in done_futures:
executor.futures.remove(f)
executor.submit_stream(query_company, name)
-
永远保持固定并发数
-
一个任务结束 → 立刻提交新任务
-
全程压力均匀,不堆积、不空闲
四、三种并发方案对比(必看)
| 方案 | 压力分布 | 稳定性 | 适用场景 |
|---|---|---|---|
| 一次性全量提交 | 瞬间爆炸 | 差(易被封) | 小数据量 |
| 分批 sleep | 波峰波谷 | 一般 | 简单脚本 |
| 平缓预热 + 流式 | 全程均匀 | 最优 | 万级大数据、接口查询、爬虫 |
五、你可以直接套用的使用规则
-
最大并发:建议 3~5(接口最安全)
-
预热间隔:0.5~1 秒
-
任务逻辑:只需要替换
query\_company\(\)为你的请求代码 -
断点续跑 / 进度保存:在任务完成后加入 Excel 写入即可
总结
- 平缓预热 = 逐个启动线程 → 消灭请求峰值
- 流式并发 = 完成一个补充一个 → 压力均匀、效率最高
本文由萧兮的博客原创发布,欢迎转载,转载务必保留原文链接。
萧兮的博客:https://www.20010515.xyz · 原文:https://www.20010515.xyz/posts/019e4ece-ba71-72c1-8cb3-4c8bed4d6844