多线程爬虫与流式并发:平缓预热设计实战

多线程爬虫与流式并发:平缓预热设计实战

多线程爬虫 / 批量接口查询:平缓预热(Warm-up)+ 流式并发 设计实战

这篇专门讲核心重点:平缓预热多线程架构,带完整可复用代码,教你如何实现无峰值、压力均匀、高效稳定的批量并发请求。


一、核心设计:什么是「平缓预热 + 流式并发」?

普通多线程:一次性把所有任务扔进线程池 → 瞬间爆发大量请求 → 被封 IP、接口报错、服务崩溃。

平缓预热架构(本文重点)

  1. 预热阶段逐个启动线程,等上一个真正开始请求了,再启动下一个 → 无请求峰值

  2. 运行阶段完成一个,补充一个 → 始终保持固定并发数 → 压力全程均匀

  3. 优势:效率最高、对接口最友好、适合万级以上大数据量


二、完整可复用核心代码(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波峰波谷一般简单脚本
平缓预热 + 流式全程均匀最优万级大数据、接口查询、爬虫

五、你可以直接套用的使用规则

  1. 最大并发:建议 3~5(接口最安全)

  2. 预热间隔:0.5~1 秒

  3. 任务逻辑:只需要替换 query\_company\(\) 为你的请求代码

  4. 断点续跑 / 进度保存:在任务完成后加入 Excel 写入即可


总结

  1. 平缓预热 = 逐个启动线程 → 消灭请求峰值
  2. 流式并发 = 完成一个补充一个 → 压力均匀、效率最高

本文由萧兮的博客原创发布,欢迎转载,转载务必保留原文链接。

萧兮的博客https://www.20010515.xyz · 原文:https://www.20010515.xyz/posts/019e4ece-ba71-72c1-8cb3-4c8bed4d6844