Python 通过gevent实现协程

时间:2022-01-15 22:19:22
#coding:utf-8-*-
'''协程(coroutine)又称微线程、纤程,是一种用户级的轻量级线程。协程有自己的寄存器上下文和栈。携程调度时,将寄存器上下文和栈
保存,在切换回来的时候恢复保存的寄存器上下文和栈。所以每次重入时,就相当于进入上一次的调用状态,在并发编程中协程与线程类似,每个协
程标识一个执行单元有自己的本地数据与其他协程共享全局数据和资源。
    协程需要用户自行编写调度逻辑,对CPU来讲协程是单线程的,所以CPU不用考虑怎么调度、切换上下文节约CPU开销,所以协程在一定程度上
又优于多线程。
   python在默认提供了yield对协程进行基本的支持,但不完全,建议使用第三方库:gevent,其提供了比较完善的协程支持。
   gevent对协程的支持,本质上来讲是greenlet在实现切换工作,greenlet的工作流程如下:
   ---加入IO操作出现阻塞,greenlet就显示的切换到另一端没有被阻塞的代码段执行,指导原先的阻塞状态消失,在切换回原来的代码段
   继续执行。
   gevent为我们自动切换协程就保证了总有greenlet在运行而不是等待IO操作,这就是协程比多线程效率高的原因'''

#gevent的使用
# from gevent import monkey
# # from gevent import monkey.patch_all
# import gevent
# import urllib2
# from idlelib.rpc import response_queue
# from greenlet import greenlet
# def run_task(url):
#     print("Visit-->%s"%url)
#     try:
#         response=urllib2.urlopen(url)
#         date=response.read()
#         print('%d bytes received from %s' %(len(date),url))
#     except Exception as e:
#         print(e)
# if __name__=="__main__":
#     urls=['https://github.com/','https://www.python.org/','http://cnblogs.com/']
#     greenlets=[gevent.spawn(run_task,url)for url in urls]
#     gevent.joinall(greenlets)
#以上主要使用了gevent中的spawn方法和joinall方法, spawn用来形成协程,joinall方法用来添加这些任务并启动
#以上三个网络操作是并发执行的而结束顺序不同,但实际只有一个线程
#-------------------------------------------------------------------------------------
#使用gevent的pool对象进行动态数量的greenlent并发管理
from gevent import  monkey
monkey.patch_all()
import urllib2
from gevent.pool import Pool
def run_task(url):
    print('Visit-->%s'%url)
    try:
        response=urllib2.urlopen(url)
        data=response.read()
        print('%d bytes reveived from %s.' %(len(data),url))
    except Exception as e:
        print(e)
    return 'url:%s-->finish'%url
if __name__=="__main__":
    pool=Pool(2)
    urls=['https://github.com/','https://www.python.org/','http://www.cnblogs.com/']
    results=pool.map(run_task,urls)
    print(results)
#以上程序中Pool对象对协程的并发数量进行了管理,先访问了前两个网址,当其中一个任务完成时才会访问第三个