协程:是单线程下的并发,又称微线程。
什么是线程?:
协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
协程的本质
协程的本质就是在单线程下,由用户自己控制一个任务遇到io阻塞了就切换另外一个任务去执行,以此来提升效率
对于不涉及io的操作,单纯的切换反而会降低效率
#并发执行
import time
def producer():
g = consumer()
next(g)
for i in range(10000000):
g.send(i)
def consumer():
while True:
res = yield
start_time = time.time()
producer()
stop_time = time.time()
print(stop_time-start_time)
#串行
import time
def producer():
res=[]
for i in range(10000000):
res.append(i)
return res
def consumer(res):
pass
start_time=time.time()
res=producer()
consumer(res)
stop_time=time.time()
print(stop_time-start_time)
总结协程的优缺点:
优点:
1、协程开销小,属于程序级别的切换,操作系统感知不到
2、单线程下可以实现并发效果, 最大限度地利用CPU
缺点
1、协程的本质是单线程下,无法利用多核优势。
2、协程是指单线程,一旦协程出现阻塞,将会阻塞整个线程。
协程的特点:
1、必须在一个单线程里实现并发
2、修改共享数据不加锁
3、用户程序自己控制保存上下文
4、一个协程遇到io操作自动切换到其他协程。
grennlet模块
并不能监听(不能遇到io自动切换)
from greenlet import greenlet
import time
def eat(name):
print(‘%s eat 1‘ % name)
time.sleep(10)
g2.switch(‘egon‘) # 切换
print(‘%s eat 2‘ % name)
g2.switch()
def play(name):
print(‘%s play 1‘ % name)
g1.switch()
print(‘%s play 2‘ % name)
g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch(‘egon‘)
gevent模块
#用法
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的
g2=gevent.spawn(func2)
g1.join() #等待g1结束
g2.join() #等待g2结束
#或者上述两步合作一步:gevent.joinall([g1,g2])
g1.value#拿到func1的返回值
遇到io自动切换
import gevent
def eat(name):
print(‘%s eat 1‘ %name)
gevent.sleep(2)
print(‘%s eat 2‘ %name)
def play(name):
print(‘%s play 1‘ %name)
gevent.sleep(1)
print(‘%s play 2‘ %name)
g1=gevent.spawn(eat,‘egon‘)
g2=gevent.spawn(play,name=‘egon‘)
g1.join()
g2.join()
#或者gevent.joinall([g1,g2])
print(‘主‘)