协程介绍
-
协程是什么
协程是微线程,他是一种用户态的轻量级线程,它的好处是没有线程切换的开销,我们开多线程,线程的上下文切换是耗费CPU的开销的,但是多协程里边,只是一个控制流调到了另外一个控制流,它还是单线程,所以协程很适合高并发,一个CPU可以支持上万的协程,因为都是在一个线程里,所以很适合进行高并发处理,Nginx为什么能支持高并发,就是因为Nginx它默认是单线程,一个线程里面支持上万个并发,协程实现了单线程实现并发的效果?
-
这种效果实现的?
答:在单线程里边,遇到I/O操作就切换,遇到I/O操作就切换,,当I/O操作处理完了之后,再自动切回去,怎么切回去的呢?
协程的使用
greenlet实现手动切换协程
from greenlet import greenlet
def test1():
print(12)
gr2.switch()
print(34)
gr2.switch()
def test2():
print(56)
gr1.switch()
print(78)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
运行结果
12
56
34
78
协程遇到I/O自动切换(gevent)
import gevent
def f1():
print('f1()在执行')
gevent.sleep(2)
print('切换回了f1()')
def f2():
print('f2()在执行')
gevent.sleep(1)
print('切换回了f2()')
def f3():
print('f3()在切换')
gevent.sleep(0) # 虽然是0s,但是还是会切换
print('切换回了f3()')
gevent.joinall([
gevent.spawn(f1),
gevent.spawn(f2),
gevent.spawn(f3),
])
结果
f1()在执行
f2()在执行
f3()在切换
切换回了f3()
切换回了f2()
切换回了f1()
这个程序只花了2s多
使用gevent注意
使用Gevent需要注意的是,上面的代码gevent.sleep
是模仿I/O操作,但是当真的遇到I/O操作,比如socket,就不好使了,需要加补丁,通过导入monkey,写上monkey.patch_all()
把当前所有的I/O操作做上标记就可以了
使用gevent实现单线程下的多socket并发
面试就可以吹一吹,我自己实现了一个socketserver,面试官问你怎么实现的,你猜,用多线程吗?只能用多线程吗?我用了协程。
什么是事件驱动模型
待补充