• python之gevent 协程操作


    gevent

    gevent是一个基于协程的python网络库,在遇到IO阻塞时,程序会自动进行切换,可以让我们用同步的方式写异步IO代码。

        因为python线程的性能问题,在python中使用多线程运行代码经常不能达到预期的效果。而有些时候我们的逻辑中又需要开更高的并发,或者简单的说,就是让我们的代码跑的更快,在同样时间内执行更多的有效逻辑、减少无用的等待。gevent就是一个现在很火、支持也很全面的python第三方协程库。
        gevent是python的一个并发框架,以微线程greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效。而且其中有个monkey类,将现有基于Python线程直接转化为greenlet(类似于打patch)。在运行时的具体流程大概就是:
        当一个greenlet遇到IO操作时,比如访问网络/睡眠等待,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。同时也因为只有一个线程在执行,会极大的减少上下文切换的成本。
     

    gevent基本使用

    # -*- coding: utf-8 -*-
    
    import gevent
    
    def f1():
        for i in range(5):
            print 'run func: f1, index: %s ' % i
            gevent.sleep(0)
    
    
    def f2():
        for i in range(5):
            print 'run func: f2, index: %s ' % i
            gevent.sleep(0)
    
    
    t1 = gevent.spawn(f1)
    t2 = gevent.spawn(f2)
    gevent.joinall([t1, t2])

    运行后输出如下图所示:

       由图中可以看出,f1和f2是交叉打印信息的,因为在代码执行的过程中,我们人为使用gevent.sleep(0)创建了一个阻塞,gevent在运行到这里时就会自动切换函数切换函数。也可以在执行的时候sleep更长时间,可以发现两个函数基本是同时运行然后各自等待。

        在实际运用的过程中,我们如果有需要通过人为sleep来增加时间间隔或者确保部分逻辑安全的时候,此处使用就很方便了。当然,更多时候我们还是在需要进行网络请求的时候使用gevent:

    # -*- coding: utf-8 -*-
    
    from gevent import monkey; monkey.patch_all()
    import gevent
    import requests
    from datetime import datetime
    
    
    def f(url):
        print 'time: %s, GET: %s' % (datetime.now(), url)
        resp = requests.get(url)
        print 'time: %s, %d bytes received from %s.' % (
            datetime.now(), len(resp.text), url)
    
    
    gevent.joinall([
            gevent.spawn(f, 'https://www.python.org/'),
            gevent.spawn(f, 'https://www.yahoo.com/'),
            gevent.spawn(f, 'https://github.com/'),
    ])

    运行上述代码,结果如下:

    由上图可以看出,程序基本在同一时间触发了对三个网站的请求,然后各自进行,分别结束。也就是当gevent发现阻塞之后,让当前急需执行,然后自动切换到了另外的请求中运行。

    加锁

    如果需要在使用gevent的时候加锁,也是非常方便的:

    # -*- coding: utf-8 -*-
    
    import gevent
    from gevent.lock import Semaphore
    
    sem = Semaphore(1)
    
    
    def f1():
        for i in range(5):
            sem.acquire()
            print 'run f1, this is ', i
            sem.release()
            gevent.sleep(1)
    
    
    def f2():
        for i in range(5):
            sem.acquire()
            print 'run f2, that is ', i
            sem.release()
            gevent.sleep(0.3)
    
    
    t1 = gevent.spawn(f1)
    t2 = gevent.spawn(f2)
    gevent.joinall([t1, t2])

    运行结果如下:

     

    由输出可以发现,程序会同时判断是否在sleep以及是否有锁两种情况,然后执行当前的最有操作。

    小结

        gevent的优势不仅仅是在代码中调用方便,厉害的是它拥有的monkey机制。假设你不愿意修改原来已经写好的python代码,但是又想充分利用gevent机制,那么你就可以用monkey来做到这一点。你所要做的就是在文件开头打一个patch,那么它就会自动替换你原来的thread、socket、time、multiprocessing等代码,全部变成gevent框架。这一切都是由gevent自动完成的。注意这个patch是在所有module都import了之后再打,否则没有效果。
        甚至在编写的Web App代码的时候,不需要引入gevent的包,也不需要改任何代码,仅仅在部署的时候,用一个支持gevent的WSGI服务器,就可以获得数倍的性能提升。

    本文简单介绍了gevent的使用,下一篇将对gevent的部分源码进行分析。

     
     
     
  • 相关阅读:
    Java自学第十天
    Java自学第九天
    Java自学第八天
    Java自学第七天
    Java自学第六天
    Java自学第五天
    Java自学第四天
    Java自学第三天
    Oracle11g RAC单节点重启
    PostgreSQL 日志处理
  • 原文地址:https://www.cnblogs.com/zhaoyingjie/p/14021404.html
Copyright © 2020-2023  润新知