一、协程简介、引子
'''
协程:异步IO,队列,缓存
Nginx效率高就是用了异步IO
协程是一种用户态的轻量级线程。又称微线程,怎么理解呢?后面会说
CPU只认识线程,不会像线程一样吧上下文保存在CPU寄存器,协程是用户控制的。
协程能保留上一次调用时的状态,单线程下实现并发效果
协程的好处:
1、无需线程上下文切换的开销,用yield的时候,只是在函数之间来回切换
2、无需原子操作锁定及同步的开销,没有异步锁之类的东西,因为协程就是单线程
3、方便切换控制流,简化编程模型
4、高并发-高扩展-低成本,一个CPU支持上万个协程都不成问题
缺点:
1、由于是单线程的无法利用多核资源,协程本质上是单线程,
2、协程需要和进程配合才能运行在多CPU上,
3、协程阻塞时会阻塞整个程序
'''
# 回顾:自己之前写的yield协程,如果生产者里面sleep(1)秒速度变慢,可以理解,看下面
# 假设下面是Nginx,来了3个请求,请求切换应该在读数据库IO的地方切换
import time
def home():
print("home")
time.sleep(3) # 读数据库
print("home_end")
def bbs():
print("bbs")
time.sleep(2) # 读数据库
print("bbs_end")
def login():
print("login")
time.sleep(1) # 写数据库
print("login_end")
'''
协程之所以能处理大并发,因为遇到IO操作就切换,因为IO耗时
那么什么时候切回去呢??应该是IO完成就切回去。怎么让系统知道IO操作完了呢??
'''
二、协程切换手动挡
'''
需要安装gevent
ps:gevent是自动挡,由于自动挡封装了手动挡
安装gevent之后,就自动有greenlet
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() # 类似于yield语句
'''
12
56
34
78
'''
三、协程切换自动挡
import gevent
'''
如果是time.sleep()就变成串行的了
'''
def foo():
print("foo_begin")
gevent.sleep(2)
print("foo_end")
def bar():
print("bar_begin")
gevent.sleep(1)
print("bar_end")
def func():
print("func_begin")
gevent.sleep(0)
print("func_end")
gevent.joinall([gevent.spawn(foo),
gevent.spawn(bar),
gevent.spawn(func)])
'''
foo_begin
bar_begin
func_begin
func_end
bar_end
foo_end
'''