使用greenlet实现协程
from greenlet import greenlet
import time
def task_1():
while True:
print("--This is task 1!--")
g2.switch() # 切换到g2中运行
time.sleep(0.5)
def task_2():
while True:
print("--This is task 2!--")
g1.switch() # 切换到g1中运行
time.sleep(0.5)
if __name__ == "__main__":
g1 = greenlet(task_1) # 定义greenlet对象
g2 = greenlet(task_2)
g1.switch() # 切换到g1中运行
# --This is task 1!--
# --This is task 2!--
# --This is task 1!--
# --This is task 2!--
# --This is task 1!--
# --This is task 2!--
# --This is task 1!--
# --This is task 2!--
greenlet已经实现了协程,但是这个需要人工切换,很麻烦。python中还有一个比greenlet更强大的并且能够自动切换任务的模块gevent,其原理是当一个greenlet遇到IO(比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程 ,就保证总有greenlet在运行,而不是等待IO。
import gevent
def task_1(num):
for i in range(num):
print(gevent.getcurrent(), i)
gevent.sleep(1) # 模拟一个耗时操作,注意不能使用time模块的sleep
if __name__ == "__main__":
g1 = gevent.spawn(task_1, 5) # 创建协程
g2 = gevent.spawn(task_1, 5)
g3 = gevent.spawn(task_1, 5)
g1.join() # 等待协程运行完毕
g2.join()
g3.join()
上述结果,在不添加gevent.sleep(1)时,是3个greenlet依次运行,而不是交替运行的。在添加gevent.sleep(1)后,程序运行到这后,交出控制权,执行下一个协程,等待这个耗时操作完成后再重新回到上一个协程,运行结果时交替运行。
monkey补丁 不必强制使用gevent里面的sleep、sorcket等等了
from gevent import monkey
import gevent
import random
import time
def task_1(name):
for i in range(5):
print(name, i)
time.sleep(1) # 协程遇到耗时操作后会自动切换其他协程运行
def task_2(name):
for i in range(3):
print(name, i)
time.sleep(1)
if __name__ == "__main__":
monkey.patch_all() # 给所有的耗时操作打上补丁
gevent.joinall([ # 等到协程运行完毕
gevent.spawn(task_1, "task_1"), # 创建协程
gevent.spawn(task_2, "task_2")
])
print("the main thread!")
# task_1 0
# task_2 0
# task_1 1
# task_2 1
# task_1 2
# task_2 2
# task_1 3
# task_1 4
# the main thread!