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   星河赵  阅读(1263)  评论(0编辑  收藏  举报

编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
历史上的今天:
2016-11-22 怎么使用jquery判断一个元素是否含有一个指定的类(class)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示