协程,又称微线程,纤程。英文名Coroutine。
一个程序可以包含多个协程,可以对比与一个进程包含多个线程,因而下面我们来比较协程和线程。我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程由当前协程来控制。
之前我们学习的generator中yield可以一定程度上实现协程
import time
def eat():
print("开始吃包子了")
while True:
n = yield
print("%s被吃掉了"%n)
def make():
g = eat()
g.__next__()
for index in range(10):
time.sleep(1)
print("包子%d号已经做好了"%index)
g.send("包子%d号"%index)
在吃包子和做包子角色之间来回切换,这就是一个简单的协程。接下来将讲述一个新的模块:gevent
greenlet
import time
from greenlet import greenlet
def task1():
print("task1")
t2.switch() # 切换到任务2
print("task1 copy")
t2.switch() # 切换到任务2
def task2():
print("task2")
t1.switch() # 切换到任务1
print("task2 copy")
t1.switch() # 切换到任务1
t1 = greenlet(task1)
t2 = greenlet(task1)
t1.switch() # 切换至任务1
执行结果:
task1
task2
task1 copy
task2 copy
greenlet可以实现协程,不过每一次都要人为的去指向下一个该执行的协程,显得太过麻烦。python还有一个比greenlet更强大的并且能够自动切换任务的模块gevent
gevent
gevent每次遇到io操作,需要耗时等待时,会自动跳到下一个协程继续执行
import gevent
def task1():
print("task1")
gevent.sleep(1)
print("task1 copy")
gevent.sleep(1)
def task2():
print("task2")
gevent.sleep(1)
print("task2 copy")
gevent.sleep(1)
def task3():
print("task3")
gevent.sleep(1)
print("task3 copy")
gevent.sleep(1)
if __name__ == "__main__":
gevent.joinall(
[
gevent.spawn(task1),
gevent.spawn(task2),
gevent.spawn(task3)
]
)
执行结果:
task1
task2
task3
task1 copy
task2 copy
task3 copy
当有IO操作是需导入monkey模块,调用monkey.patch_all()方法来匹配所有IO操作。