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是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()
分类:
Python常用方法
, 面试常见问题
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于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)