python之协程详解编程语言

协程又叫做微线程,协程是一种用户态的轻量级的线程,协程拥有自己的的寄存器的上下文和栈,协程调度切换时,将寄存器上下文和栈保存
到其他地方,在切换回来后,恢复之前保存的寄存器的上下文关系,因此协程能保留上一次调用的状态,每次过程重入的时候,就相当于
进入上一次调用的状态

协程一定在单线程中,协程的切换是在线程中切换,和单个线程在cpu之间不停的切换是一样的
但是线程切换是cpu控制的,而协程的切换是用户控制的,操作系统根本无感知;
协程的切换比线程的切换速度要快,效率要高

协程的好处
1、无需线程上下文切换的开销
2、无需原子操作锁定及同步的开销,因为协程是串行的
3、方便切换控制流,简化编程模型
4、高并发,高扩展,低成本,一个cpu支持上万个协程没有问题,所以非常适合高并发处理

协程的缺点
1、无法利用多核的优势,但是协程和进程配合就可以使协程运行在不同的cpu上
2、只要一个协程阻塞(Blocking),就会阻塞整个协程,因为协程是串行的,这个问题必须要解决,才能让协程大范围应用
解决方法:
1、如果遇到io操作,则进行协程切换,可以用gevent来实现


我们来看一段代码
#Gevent主要是解决协程阻塞的问题,Gevent是一个第三方库,可以轻松通过Gevent实现并发同步 
# 或者异步编程,在gevent中用到的主要模式是Greenlet,他是以C扩展模块形式接入Python的轻量级 
# 协程,Greenlet全部运行在主程序操作系统进程的内部,但是被协作式调度
import gevent import time def foo(): print("/033[41;1mrunning in foo/033[0m") gevent.sleep(1) #触发协程切换 # time.sleep(1) print("/033[41;1mExplicit context switch to foo aga/033[0m") def Bar(): print("/033[42;1mExplicit context to bar/033[0m") gevent.sleep(2) #触发协程切换 # time.sleep(2) print("/033[42;1mImplicit context switch back to bar/033[0m") def Car(): print("/033[43;1mExplicit context to bar/033[0m") gevent.sleep(3) #触发协程切换 # time.sleep(3) print("/033[43;1mImplicit context switch back to bar/033[0m") gevent.joinall( [gevent.spawn(foo), gevent.spawn(Bar), gevent.spawn(Car) ] ) # 1、running in foo # 2、Explicit context to bar # 3、Explicit context to bar # 4、Explicit context switch to foo aga # 5、Implicit context switch back to bar # 6、Implicit context switch back to bar #先同时打印1,然后遇到gevent,就会进行协程切换,切换到协程2,打印2,然后遇到gevent,又会进行协程切换,打印3,又遇到gevent,再次进行协程切换 #切换到协程1,这个时候就算

使用urllib+gevent实现多协程的网页爬虫

from gevent import monkey; monkey.patch_all() 
import gevent 
import urllib.request 
 
#可以简单的爬网页的一个模块 
 
def f(url): 
    print("GET:[%s]" %(url)) 
    resp = urllib.request.urlopen(url) 
    data = resp.read() 
    print("[%d] bytes received from %s" %(len(data),url)) 
 
gevent.joinall( 
    [gevent.spawn(f,"http://www.baidu.com/"), 
     gevent.spawn(f,"http://www.python.org/"), 
     gevent.spawn(f,"http://www.sina.com/"), 
     gevent.spawn(f,"http://www.163.com/"), 
    ] 
) 

  

结果如下,遇到阻塞就会自动跳转到其他的协程,这个阻塞gevent会自动判断的

GET:[http://www.baidu.com/] 
GET:[http://www.python.org/] 
GET:[http://www.sina.com/] 
GET:[http://www.163.com/] 
[111488] bytes received from http://www.baidu.com/ 
[601132] bytes received from http://www.sina.com/ 
[660092] bytes received from http://www.163.com/ 
[48713] bytes received from http://www.python.org/ 

  

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/20873.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论