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

    协程,又称微线程,是用户级的轻量级线程。协程拥有自己的寄存器上下文和栈,调度切换时,将寄存器上下文保存在其他地方,切回来恢复。因此,协程能保留上一次调用的状态。

    • 在并发编程中,协程与线程类似,每个协程有自己的本地数据,与其他协程共享全局数据和其他资源
    • 协程需要用户自己编写调度逻辑,对CPU来说,协程其实是单线程,CPU不需要考虑怎样调度。

    python通过yield提供了对协程的基本支持,但不完全,而使用第三方gevent库是更好的选择。gevent是基于协程的python网络函数库。

    • 使用greenlet在libev事件循环顶部提供了一个高级别并发性的api,主要特点:

      • 基于libev的快速事件循环,linux上是epoll机制
      • 基于greenlet的轻量级执行单元
      • API复用了python标准库里的内容
      • 支持SSL的协作式sockets
      • 可通过线程池或c-ares实现DNS查询
    • 通过monkey patching功能使得第三方模块变成协作式。

      • gevent对协程的支持,本质上是greenlet在实现切换工作。greenlet工作流程如下:

        • 假如进行访问网络IO操作时,出现阻塞,greenlet就显示切换到另一段没有被阻塞的代码段执行,直到原先的阻塞状况消失,再自动切回原来的代码段继续执行。串行方式

        • 有了gevent为我们自动切换协程,就保证greenlet在运行,而不是等待IO。这就是协程比一般多线程高效的原因

        • 由于切换是在IO操作时自动完成,所以gevent需要修改python自带的一些标准库,将一些常见的阻塞,如socket、select等地方实现跳转,这一过程启动通过monkey patch完成

    #!coding:utf-8
    from gevent import monkey; monkey.patch_all()
    import gevent
    import urllib2
    
    def run_task(url):
        print 'Visit --> %s' %url
        try:
            response = urllib2.urlopen(url)
            data = response.read()
            print '%d bytes received from %s.' % (len(data),url)
        except Exception,e:
            print e
    
    if __name__=='__main__':
        urls = ['https://github.com/','https://www.python.org/','http://www.cnblogs.com/']
        # 用来形成协程
        greenlets = [gevent.spawn(run_task, url) for url in urls]
        # 添加这些协程任务,并且启动运行
        gevent.joinall(greenlets)
    
    C:Python27python.exe F:/python_scrapy/python_study/coroutine_greenlet.py
    Visit --> https://github.com/
    Visit --> https://www.python.org/
    Visit --> http://www.cnblogs.com/
    48814 bytes received from https://www.python.org/.
    59963 bytes received from https://github.com/.
    46880 bytes received from http://www.cnblogs.com/.
    
    Process finished with exit code 0
    
    
    • 以上程序主要用了gevent中的spawn 方法和joinall 方法,spawn方法可以看做是用来形成协程,joinall 方法就是添加这些协程任务,并且启动运行。三个网络操作时并发执行的,而且结束顺序不同,但其实只
      有一个线程
      gevent 中也提供了对池的支持,对greenlet进行并发管理(限制并发数),就可以使用池,这在处理大量的网络和IO操作时时非常必要的,程序改写如下:
    #!coding:utf-8
    from gevent import monkey; monkey.patch_all()
    import gevent
    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 received from %s.' % (len(data),url)
        except Exception,e:
            print e
        return 'url:%s ---》finish'%url
    
    if __name__=='__main__':
        urls = ['https://github.com/','https://www.python.org/','http://www.cnblogs.com/']
        pool = Pool(2)
        results = pool.map(run_task, urls)
        print results
    
    
    • 运行结果:
    C:Python27python.exe F:/python_scrapy/python_study/coroutine_greenlet.py
    Visit --> https://github.com/
    Visit --> https://www.python.org/
    48814 bytes received from https://www.python.org/.
    Visit --> http://www.cnblogs.com/
    59855 bytes received from https://github.com/.
    46891 bytes received from http://www.cnblogs.com/.
    ['url:https://github.com/ ---xe3x80x8bfinish', 'url:https://www.python.org/ ---xe3x80x8bfinish', 'url:http://www.cnblogs.com/ ---xe3x80x8bfinish']
    
    Process finished with exit code 0
    
    
    • Pool对象确实对协程的并发数量进行管理,先访问了前两个网址,当其中一个完成时,才会执行第三个
  • 相关阅读:
    c# winForm 圆角Panel
    C# WinForm开发系列 ListBox/ListView/Panel
    WCF RIA Service实体类的自定义复杂类型属性在客户端不可见
    与用户深入交互 不做机器人般的设计师
    The Big List of What’s New or Improved in Silverlight 5
    Instantiating a Silverlight Plugin (Using CreateSilverlight.js and Silverlight.js)
    不用js也能创建silverlight
    WCF中使用HttpContext.Current的办法
    去除字符串空格,各类型验证,获取url参数等
    Understanding WCF Services in Silverlight 2
  • 原文地址:https://www.cnblogs.com/guguobao/p/9399980.html
Copyright © 2011-2022 走看看