Python gevent 常规用法

gevent 是 Python 协程(Coroutine) 库,基于 greenlet 实现,用于IO 密集型任务(爬虫、网络请求、文件读写),单线程就能并发,性能极高。


一、安装

pip install gevent
# 慢的话用国内源
pip install gevent -i https://pypi.tuna.tsinghua.edu.cn/simple

二、核心概念

  1. 协程:单线程内并发,切换开销极小
  2. gevent:自动识别 IO 阻塞,自动切换协程
  3. 猴子补丁(monkey patch):把 Python 默认阻塞 IO 变成非阻塞

三、最常用写法

1. 基础协程任务

# 第一步:必须先打猴子补丁(关键)
from gevent import monkey
monkey.patch_all()

import gevent
import time

def task(name):
    print(f"任务 {name} 开始")
    # gevent.sleep 是协程延时,会自动切换任务
    # 不能用 time.sleep(会阻塞整个线程)
    gevent.sleep(2)
    print(f"任务 {name} 结束")

if __name__ == '__main__':
    # 记录开始时间
    start = time.time()

    # 创建协程
    g1 = gevent.spawn(task, "A")
    g2 = gevent.spawn(task, "B")
    g3 = gevent.spawn(task, "C")

    # 等待所有协程执行完毕
    gevent.joinall([g1, g2, g3])

    print(f"总耗时:{time.time() - start:.2f} 秒")

运行结果

任务 A 开始
任务 B 开始
任务 C 开始
任务 A 结束
任务 B 结束
任务 C 结束
总耗时:2.01 秒

四、gevent 常用 API 大全

1. 创建协程

g = gevent.spawn(函数名, 参数1, 参数2...)

2. 等待协程

gevent.joinall([g1, g2])  # 等待列表中所有协程完成
g.join()  # 等待单个协程

3. 协程延时

gevent.sleep(秒数)  # 协程友好,自动切换
# ❌ 禁止用 time.sleep()(会阻塞所有协程)

4. 获取协程返回值

def func():
    return "结果"

g = gevent.spawn(func)
gevent.joinall([g])
print(g.value)  # 获取返回值

5. 捕获协程异常

try:
    g = gevent.spawn(危险函数)
    g.join()
except Exception as e:
    print("出错:", e)

五、gevent 并发爬虫(最常用场景)

from gevent import monkey
monkey.patch_all()

import gevent
import requests

def fetch(url):
    print(f"正在请求:{url}")
    res = requests.get(url)
    print(f"{url} 响应长度:{len(res.text)}")

if __name__ == '__main__':
    urls = [
        "https://www.baidu.com",
        "https://www.qq.com",
        "https://www.jd.com"
    ]

    # 批量创建协程
    tasks = [gevent.spawn(fetch, url) for url in urls]
    gevent.joinall(tasks)

3 个网络请求几乎同时发出,速度极快


六、gevent 队列(生产者消费者模型)

from gevent import monkey
monkey.patch_all()
import gevent
from gevent.queue import Queue

q = Queue(maxsize=3)

def producer():
    for i in range(5):
        q.put(f"数据{i}")
        print("生产:数据", i)
        gevent.sleep(0.5)

def consumer():
    while True:
        data = q.get()
        print("消费:", data)
        gevent.sleep(1)

gevent.joinall([
    gevent.spawn(producer),
    gevent.spawn(consumer)
])

七、必须记住的 3 条规则(不遵守必出 BUG)

  1. 第一行必须打补丁
    from gevent import monkey
    monkey.patch_all()
    
  2. 不能用 time.sleep(),必须用 gevent.sleep()
  3. 只适合 IO 密集型(网络、文件、数据库),不适合 CPU 计算

八、gevent 与 线程/进程 对比

方式开销并发数适用场景
进程CPU 密集
线程IO 密集
gevent 协程极小极高(上万)IO 密集(首选)

总结

  1. geventPython 最高效的 IO 并发方案
  2. 必须加 monkey.patch_all()
  3. 核心 API:spawnjoinallsleep
  4. 适合:爬虫、接口请求、socket 服务
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐