zoukankan      html  css  js  c++  java
  • Python协程

    Gevent是一个基于Greenlet实现的网络库,通过greenlet实现协程。基本思想是一个greenlet就认为是一个协程, 当一个greenlet遇到IO操作的时候,比如访问网络,就会自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO操作。

    1. Greenlet是作为一个C扩展模块,它封装了libevent事件循环的API,可以让开发者在不改变编程习惯的同时,用同步的方式写异步IO的代码。

    from urllib import request
    import gevent
    
    def test(url):
        print('[%s]Get: %s'% (gevent.getcurrent(), url))
        response = request.urlopen(url)
        content = response.read().decode('utf8')
        print('[%s]%d bytes received from %s.' % (gevent.getcurrent(), len(content), url))
    
    if __name__ == '__main__':
        gevent.joinall([
            gevent.spawn(test, 'http://www.baidu.com'),
            gevent.spawn(test, 'http://httpbin.org/ip'),
            gevent.spawn(test, 'http://httpbin.org/uuid')
        ])

    执行结果:

    2. 可以看到3个greenlet是依次运行,而不是交替运行。要让greenlet交替运行,可以通过gevent.sleep()交出控制权.

    from urllib import request
    import gevent
    
    def test(url):
        print('[%s]Get: %s'% (gevent.getcurrent(), url))
        response = request.urlopen(url)
        content = response.read().decode('utf8')
        gevent.sleep(1)
        print('[%s]%d bytes received from %s.' % (gevent.getcurrent(), len(content), url))
    
    if __name__ == '__main__':
        gevent.joinall([
            gevent.spawn(test, 'http://www.baidu.com'),
            gevent.spawn(test, 'http://httpbin.org/ip'),
            gevent.spawn(test, 'http://httpbin.org/uuid')
        ])

    执行结果:

    3. 在实际的代码里,我们不会用gevent.sleep()去切换协程,而是在执行到IO操作时gevent会自动完成。所以gevent需要将Python自带的一些标准库的运行方式由阻塞式调用变为协作式运行。这一过程在启动时通过monkey patch完成.

    from gevent import monkey; monkey.patch_all() # 协作式运作
    from urllib import request
    import gevent
    
    def test(url):
        print('[%s]Get: %s'% (gevent.getcurrent(), url))
        response = request.urlopen(url)
        content = response.read().decode('utf8')
        print('[%s]%d bytes received from %s.' % (gevent.getcurrent(), len(content), url))
    
    if __name__ == '__main__':
        gevent.joinall([
            gevent.spawn(test, 'http://www.baidu.com'),
            gevent.spawn(test, 'http://httpbin.org/ip'),
            gevent.spawn(test, 'http://httpbin.org/uuid')
        ])

    执行结果:

     三个网络IO操作时并发执行的,而且结束顺序不同,但是只有一个线程。

    协程和多线程的差异在于多线程的切换需要靠操作系统来完成,当线程越来越多的时候切换的成本会很高,而协程是在一个线程内切换的,切换过程由我们自己控制,因此开销小的多,这就是协程和多线程的根本差异。

  • 相关阅读:
    NYOJ 38布线问题
    NYOJ 106背包问题
    基于贪心算法的几类区间覆盖问题 nyoj 12喷水装置(二) nyoj 14会场安排问题
    HDOJ 2546饭卡(01背包问题)
    FBI树-数据结构(二叉树)
    二叉树遍历(flist)(二叉树,已知中序层序,求先序)
    求先序排列(二叉树已知中序和后序,求先序)
    滑雪(dp)
    Python——plot可视化数据,作业8(python programming)
    数据库SQL语言学习----左外连接,右外连接,外连接,自然连接的形象对比
  • 原文地址:https://www.cnblogs.com/yunxintryyoubest/p/14328084.html
Copyright © 2011-2022 走看看