13.协程
协程:又称微线程,纤程,是一种用户态的轻量级线程,能够在单线程下跑出并发的状态
协程拥有自己的寄存器上下文和栈,协程调度切换时,将寄存器上下文和栈保存在其他地方,在切回来时,恢复先前保存的寄存器上下文和栈
因此:协程能够保存上一次调用时的状态,每次过程重入时,相当于进入上一次调用的状态
协程的优点和缺点:
优点:
无需线程上下文切换的开销
方便切控制流
无需原子操作锁定即同步的开销
高并发+高扩展+低成本:一个cpu支持上万的协程都不是问题
缺点:
无法利用多核cpu资源 解决方法;协程+多进程
使用yield可以实现简单的底层协程,通过yield来停止一个进程切换到另一个进程
实现协程:
pyhton提供了gevent模块来实现协程,需要提前安装
switch 协程之间的转换靠switch执行,如果再跳转回来,直接执行该switch的下一句代码
gevent.sleep() 模拟系统发生IO阻塞
gevent.joinall() 激活程序
代码如下:
from greenlet import greenlet
def test1():
print(12)
gr2.switch() # 跳转到test2()函数执行,如果再跳转回来,直接执行该句的下一句
print(34)
gr2.switch()
def test2():
print(56)
gr1.switch()
print(78)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
#这类语句的作用是跳转到某个函数的语句中执行,如本是跳转执行test()函数
执行结果:
12
56
34
78
使用协程来写爬虫:
import gevent from gevent import monkey #补丁 import requests import time headers={ 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36' } def get_html(url): print('get:%s'%url) resp=requests.get(url,headers=headers) test=resp.content print('%d bytes recevied from %s'%(len(test),url)) monkey.patch_all() #在协程程序中,一旦cpu进入IO阻塞状态,cpu的线程就会切换到其他程序,因此要时刻监听cpu,在windows系统中,对cpu的监听不够严谨,加入此代码可以最大程度的监听cpu是否进入io阻塞的状态
print(time.ctime()) #开始事件
gevent.joinall([ #激活协程程序
gevent.spawn(get_html,'https://www.python.org/'),
gevent.spawn(get_html,'https://ww.yahoo.com/'),
gevent.spawn(get_html,'https://github.com'),
])
print(time.ctime()) #结束事件
使用joinall和spawn可以确保cpu一旦进入阻塞状态,就会切换带其他代码中,可以大幅度的提高程序的执行速度

浙公网安备 33010602011771号