Python 之并发编程之协程
一.协程
'''
def gen():
for i in range(10):
yield i
# 初始化生成七函数 返回生成器对象,简称生成器
mygen = gen()
for i in mygen:
print(i)
'''
# (1) 用协程改写成生产者消费者
'''
def producer():
for i in range(100):
yield i
def consumer():
g = producer()
for i in g:
print(i)
'''
# (2) 协程的具体实现
from greenlet import greenlet
import time
'''
switch 利用它进行任务的切块,一般在阻塞的时候切块
只能默认手动切换
缺陷: 不能规避io,不能自动实现遇到阻塞就切换
'''
"""
def eat():
print("eat one")
# 手动切换play这个协程中
g2.switch()
time.sleep(1)
print("eat two")
def play():
print("play one")
time.sleep(1)
print("play two")
g1.switch()
g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch()
'''
eat one
play one
play two
eat two
'''
"""
# (3) 缺陷:gevent不能够识别time.sleep 是阻塞
"""
import gevent
# gevent 其中有一个spawn 类似于switch ,也是切换任务的
import time
def eat():
print("eat one")
time.sleep(1)
print("eat two")
def play():
print("play one")
time.sleep(1)
print("play two")
# 利用gevent 创建协程对象g1
g1 = gevent.spawn(eat)
#利用gevent创建协程对象g2
g2 = gevent.spawn(play)
# 协程的阻塞是join 等待当前协程执行完毕之后,再向下执行
g1.join() #阻塞直到g1协程执行完毕
g2.join() #阻塞直到g2协程执行完毕
print("主线程执行完毕")
"""
# (4) 进阶 用gevent.sleep 来取代time.sleep()
'''
import gevent
def eat():
print("eat one")
gevent.sleep(1)
print("eat two")
def play():
print("play one")
gevent.sleep(1)
print("play two")
g1 = gevent.spawn(eat)
g2 = gevent.spawn(play)
g1.join()
g2.join()
print("主线程执行完毕")
'''
# (5) 终极解决识别问题
# spawn gevent 中spawn 遇到阻塞会自动切换协程任务
from gevent import monkey
# 把patch_all 下面引入的所有模块中的阻塞识别出来
monkey.patch_all()
import time
import gevent
def eat():
print("eat one")
time.sleep(1)
print("eat two")
def play():
print("play one")
time.sleep(1)
print("play two")
g1 = gevent.spawn(eat)
g2 = gevent.spawn(play)
g1.join()
g2.join()
print("主进程执行结束...")
二.协程例子