You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中替代multiprocessing的高效资源友好批量URL爬取方案(非线程)

高效且资源友好的爬虫替代方案

1. AsyncIO + 异步HTTP库(如aiohttp)

爬虫属于IO密集型任务,异步IO是当前最适配的方案之一,基于单线程(或少量线程)的协程模型,资源占用极低,可同时处理数千个并发请求。

  • 核心逻辑:用asyncio实现事件循环,配合aiohttp发起异步HTTP请求,彻底避免进程/线程切换的额外开销。
  • 示例代码片段:
import asyncio
import aiohttp

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, f"https://example.com/record/{i}") for i in range(10000)]
        results = await asyncio.gather(*tasks)
        # 后续处理爬取结果

if __name__ == "__main__":
    asyncio.run(main())
  • 优势:单进程即可支撑极高并发,内存、CPU占用远低于多进程方案,完全适配百万级记录的爬取需求。

2. 优化版concurrent.futures.ProcessPoolExecutor

如果爬虫流程中包含少量CPU密集型操作(比如复杂HTML/JSON解析),可使用ProcessPoolExecutor但优化参数,避免无节制创建进程:

  • 关键优化:将max_workers设置为CPU核心数的1-2倍(而非30-50),利用CPU亲和性减少上下文切换;配合任务分批提交,避免一次性压入百万任务导致内存暴涨。
  • 示例代码片段:
from concurrent.futures import ProcessPoolExecutor
import requests

def crawl_record(record_id):
    url = f"https://example.com/record/{record_id}"
    response = requests.get(url)
    # 解析并返回结果

def main():
    record_ids = range(1000000)
    # 按CPU核心数设置进程数,例如4核设为8
    with ProcessPoolExecutor(max_workers=8) as executor:
        # 分批提交任务,控制内存占用
        for chunk in chunks(record_ids, 1000):
            results = executor.map(crawl_record, chunk)
            # 处理当前批次结果

def chunks(lst, n):
    for i in range(0, len(lst), n):
        yield lst[i:i+n]
  • 优势:兼顾CPU密集型处理的效率,同时严格控制资源占用,比手动创建大量进程更合理。

3. Gevent(协程猴子补丁方案)

Gevent是基于libev的协程库,通过猴子补丁(monkey-patch)将同步IO接口转为异步,无需大幅修改原有同步代码即可实现高并发:

  • 核心逻辑:用gevent.monkey.patch_all()替换标准库的同步IO接口,再用gevent.pool.Pool控制并发数。
  • 示例代码片段:
from gevent import monkey, pool
import requests

monkey.patch_all()

def crawl_record(record_id):
    url = f"https://example.com/record/{record_id}"
    response = requests.get(url)
    # 解析结果

def main():
    record_ids = range(1000000)
    p = pool.Pool(1000)  # 可设置数千并发,资源占用仍保持低位
    results = p.map(crawl_record, record_ids)
    # 处理结果

if __name__ == "__main__":
    main()
  • 优势:对原有同步代码改造极小,可快速实现高并发,资源占用远低于多进程方案。

4. multiprocessing.Pool + 任务队列限流

如果坚持使用多进程方案,可改用multiprocessing.Pool而非手动创建大量进程,同时通过任务队列控制并发任务数:

  • 关键:设置processes为CPU核心数的合理倍数,用imap或imap_unordered分批获取结果,避免一次性加载所有任务。
  • 示例代码片段:
from multiprocessing import Pool
import requests

def crawl_record(record_id):
    url = f"https://example.com/record/{record_id}"
    response = requests.get(url)
    return response.text

def main():
    record_ids = range(1000000)
    with Pool(processes=8) as pool:
        # 迭代获取结果,降低内存占用
        for result in pool.imap_unordered(crawl_record, record_ids, chunksize=100):
            # 处理单条结果
            pass
  • 优势:自动管理进程生命周期,避免进程泄漏,合理控制资源占用。

内容的提问来源于stack exchange,提问作者Volatil3

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 20:51:18