gevent
是 Python 中的一个用于并发编程的库,主要通过 协程(coroutines) 实现高效的并发任务管理。它利用了 Greenlets,这是一种轻量级的协程,可以在单个线程中并发执行多个任务,从而避免线程上下文切换的开销。gevent
的核心是基于事件循环的协程调度,并且它通过自动打补丁的方式使得阻塞的 I/O 操作变成异步的。
Gevent 的核心功能
- 协程:通过
gevent.spawn()
创建协程,并让多个任务并发运行。 - 协程的调度和切换:通过
gevent.sleep()
进行手动调度,或者在 I/O 操作中自动调度。 - 打补丁:通过
gevent.monkey.patch_all()
替换 Python 标准库中的一些阻塞调用,使得它们可以异步执行。 - 并发 I/O 操作:
gevent
适合网络 I/O 密集型应用(如 Web 服务器),而不是 CPU 密集型任务。
基本使用示例
import gevent
from gevent import monkey
# 打补丁,使标准库的阻塞 I/O 操作可以异步执行
monkey.patch_all()
import time
def task_1():
print('Task 1 start')
gevent.sleep(2)
print('Task 1 end')
def task_2():
print('Task 2 start')
gevent.sleep(1)
print('Task 2 end')
def task_3():
print('Task 3 start')
gevent.sleep(0.5)
print('Task 3 end')
# 创建协程
tasks = [
gevent.spawn(task_1),
gevent.spawn(task_2),
gevent.spawn(task_3)
]
# 等待所有协程完成
gevent.joinall(tasks)
重要概念
-
协程 (Greenlet):
gevent
使用 Greenlet 实现协程,它是轻量级的执行单元,可以并发执行任务。通过gevent.spawn(func)
来启动协程。
-
I/O 异步:
gevent
可以通过打补丁的方式,将标准库的阻塞 I/O 操作转换为异步操作,例如socket
、time.sleep()
等,使程序无需线程也能高效处理 I/O 密集型任务。
-
事件循环:
- Gevent 基于事件循环调度任务,避免了线程切换带来的性能开销。
Gevent 适用场景
- 网络 I/O 密集型应用:例如 Web 服务器、WebSocket 服务器、爬虫等。
- 任务调度:可以用于处理需要并发执行的小任务。
Gevent 与多线程的对比
- Gevent 使用协程(轻量级的 Greenlet)进行并发执行,不需要多线程上下文切换。
- Gevent 的协程是用户级别的调度,不依赖于操作系统调度器,因此在 I/O 密集型任务中比多线程更高效。
常见功能
-
spawn: 用来启动一个协程。
g = gevent.spawn(func, *args, **kwargs)
-
join: 用来等待一个协程执行结束。
g.join()
-
joinall: 用来等待一组协程结束。
gevent.joinall([g1, g2, g3])
-
sleep: 让当前协程让出控制权,进入可调度状态。
gevent.sleep(seconds)
打补丁
from gevent import monkey
monkey.patch_all()
这个方法替换 Python 标准库中的阻塞调用,使得它们可以被 gevent 异步化,适用于 socket、time.sleep 等场景。
Gevent 与同步阻塞操作
如果不打补丁,标准的 Python 函数(如 time.sleep()
和 socket.recv()
)是同步阻塞的,这意味着在执行这些操作时会阻塞整个线程。而使用 gevent.monkey.patch_all()
后,这些操作会被替换为非阻塞版本,使得协程可以在等待 I/O 的过程中执行其他任务。
gevent
是处理 I/O 密集型任务非常高效的工具,避免了传统线程带来的开销。