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基本使用 不加gevent.monkey是顺序执行起不到协程的作用

 

# -*- 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])

 

运行后输出如下图所示是顺序执行,并没有切换:

 

gevent的正确使用

import gevent
import gevent.pool
import gevent.monkey

gevent.monkey.patch_all()  # 分布式冲突
import requests


def download_img(t_event_data):
    """
    保存图片到本地
    :return:
    """
    try:
        index = t_event_data["index"]
        num = t_event_data["num"]
        r = requests.get("https://wwww.baidu.com")
        print("index:{} num:{}".format(index, num))

    except Exception as e:
        print("下载异常:{}".format(e))


def main():
    try:
        num_list = [i for i in range(1, 100)]  # 相当于起了100个协程池
        gevent_data_list = []

        for index, num in enumerate(num_list):
            t_event_data = {}
            t_event_data["index"] = index
            t_event_data["num"] = num
            gevent_data_list.append(gevent.spawn(download_img, t_event_data))

        gevent.joinall(gevent_data_list)
    except Exception as e:
        print("异常 {}".format(e))


if __name__ == "__main__":
    main()

 

gevent 协程池的使用

协程池相对要好用些,可以自定义一个协程池指定个数,把待执行的队列(列表)丢进去,即可执行

gevent.joinall()等待所有协程结束 timeout设置每个协程超时时间

import gevent
import gevent.pool
import gevent.monkey

gevent.monkey.patch_all()  # 分布式冲突
import requests


def download_img(t_event_data):
    """
    保存图片到本地
    :return:
    """
    try:
        index = t_event_data["index"]
        num = t_event_data["num"]
        r = requests.get("https://wwww.baidu.com")
        print("index:{} num:{}".format(index, num))

    except Exception as e:
        print("下载异常:{}".format(e))


def main():
    try:
        num_list = [i for i in range(1, 100)] #待处理的数据
        gevent_data_list = []

        mypool = gevent.pool.Pool(10)  # 定义协程池个数

        for index, num in enumerate(num_list):
            t_event_data = {}
            t_event_data["index"] = index
            t_event_data["num"] = num
            gevent_data_list.append(t_event_data)
            # 协程设置超时时间       
            #gevent_data_list.append(mypool.spawn(t_event_data, t_event_data)) 
        result = mypool.map(download_img, gevent_data_list)
        #result = gevent.joinall(gevent_data_list, timeout=5) # timeout每个协程设置超时时间
        print(result)
    except Exception as e:
        print("异常 {}".format(e))


if __name__ == "__main__":
    main()

 

 

 

 

 

posted on 2020-11-22 21:04  星河赵  阅读(1233)  评论(0编辑  收藏  举报

导航