zoukankan      html  css  js  c++  java
  • python学习笔记 day40 协程(二)

    1. 协程---多个协程 执行函数其实仍然是在同一个线程内完成的,只不过多个协程之间仍然是异步并发执行的

    from gevent import monkey;monkey.patch_all() # 加上这句话,gevent遇到其他模块(time,socket等IO操作)的IO 需要等待时 就会切换协程
    import gevent
    from threading import current_thread
    import time
    def func1():
        print(current_thread().name)  # 打印当前线程名(其实协程并不是线程,多个协程是在同一个线程内完成的)
        print("hello,xuanxuan")
        time.sleep(1)
        print("bye")
    
    def func2():
        print(current_thread().name)  # 打印当前线程名(其实开的是协程,多个协程是在同一个线程内执行的)
        print("hello,xixi")
        time.sleep(1)
    
    g1=gevent.spawn(func1)
    g2=gevent.spawn(func2)
    gevent.joinall([g1,g2])  # 在主线程中统一关闭多个协程(但是多个协程之间仍然是并发执行的)

    运行结果:

     2. 测试有IO操作时,使用多个协程与开单线程单步执行多个任务执行效率的对比

    结论: 当需要执行的任务有很多IO操作(比如网络延时requests爬取网页,socket请求等) 开多个协程执行任务,比使用单线程单步执行多个任务(同步执行)效率要高很多;

    from gevent import monkey;monkey.patch_all()  # 保证gevent在遇到其他模块(time,requests,socket)的IO操作时可以切换协程,从而实现异步,完成时间复用
    import gevent
    import time
    
    def task(i):
        time.sleep(1)
        print(i)
    
    def sync_func():  # 同步执行
        for i in range(10):  # 有10个任务需要执行
            task(i)
    
    def async_func():
        g_lst=[]   # 把开的协程存放成一个列表,最后统一join(),主线程等待所有协程执行完毕,但是多个协程之间仍然是异步并发执行的
        for i in range(10):
            g=gevent.spawn(task,i)    # gevent.spawn(func,arg) 创建并开启一个协程(这里是开启10个协程)
            g_lst.append(g)  # 为了使多个协程之间异步并发执行
        gevent.joinall(g_lst)  # 多个协程统一join() 保证多个协程之间异步并发
    
    start=time.time()
    sync_func()
    print("单线程单步执行多个任务所需要的时间:%s"%(time.time()-start))
    
    start=time.time()
    async_func()
    print("开启多个协程执行多个任务所需要的时间是:%s"%(time.time()-start))

    运行结果:

     3. 开多个协程去爬取多个网页与单线程单步执行爬取网页的效率对比

    爬取10个网页,协程函数去发起10个网页的爬取任务,协程在爬取网页时有一定的响应时间。在等待时,如果用到协程函数,一个函数在爬取网页过程中遇到网络延时(等待IO),它不会等待,而是紧接着去执行下一个任务,这样既可以复用时间,上面的网页等着,下面的网页都已经开始执行了;

    from gevent import monkey;monkey.patch_all()   # 保证使用gevent遇到其他模块(time,socket requests等网络延时)等的IO操作时可以切换协程,从而实现多个协程并发
    import gevent
    import requests   # 爬取网页
    import time
    
    def get_url(url):
        ret=requests.get(url)
        print(url,ret.status_code,len(ret.text))  # 返回爬取网页的信息(requests.get(url).text----获取网页源代码; requests.get(url).status_code----获取网页状态码)
    
    url_lst=["http://www.baidu.com","http://www.sougou.com","http://www.python.org","http://www.qq.com","http://www.cnblog.com","http://www.mi.com"]
    g_lst=[]   # 开多个协程然后存成一个列表,最后统一join,为了保证主线程等待所有协程执行完毕,但是多个协程之间是异步并发的;
    
    def async_func():   # 开多个协程执行10个爬取网页的任务(有只可能一个协程打开一个网页时,有网络延时,它不会等,
                           # 直接开协程去请求其他的网页,在等待的过程中有可能其他网页都请求完了,从而实现时间的复用)
        for url in url_lst:
            g=gevent.spawn(get_url,url)
            g_lst.append(g)
        gevent.joinall(g_lst)  # 多个协程统一关闭(保证多个协程之间异步并发执行,从而完成时间复用)
    
    def sync_func():  # 开单线程单步执行多个任务(爬取10个网页)
        for url in url_lst:
            get_url(url)
    
    start=time.time()
    async_func()
    print("开多个协程执行爬取10个网页的任务所用时间:%s"%(time.time()-start))
    
    start=time.time()
    sync_func()
    print("开单线程单步执行爬取10个网页的任务所用时间为:%s"%(time.time()-start))

    运行结果:

     协程在响应一个网页时,有网络延时,它就可能利用这个时间去打开其他网页了,也就是时间复用,有可能利用第一个网页等待时间,把剩下所有网页的请求都发出去了;

    同步单步执行时,每执行一个网页就会等待网络延时,串行的;而协程就是在发送一个网页时,不等,因为它直到有网络延时,所以直接执行下一个任务;

    talk is cheap,show me the code
  • 相关阅读:
    执迷不悟
    splunk设置索引周期和索引大小
    下载地址sqlserver2008r2
    蓝牙
    1、IdentityServer4
    翻译名义集
    sql 字符取数字
    Aerial Images Dataset 航空图像数据集 收集
    基于VGG16模型对猫狗分类任务进行迁移学习
    Apollo配置中心
  • 原文地址:https://www.cnblogs.com/xuanxuanlove/p/9800519.html
Copyright © 2011-2022 走看看