异步编程利器:深入解析 Python 异步并发库 Gevent
在现代 Python 应用开发中,并发编程 是提高程序性能、处理多个任务的关键手段之一。虽然 Python 有原生的多线程、多进程模块,但这些模块存在一些限制,比如全局解释器锁(GIL)会影响多线程程序的执行效率。此外,编写并发程序通常也比写串行代码复杂得多。为了简化并发编程并提高效率,许多 Python 开发者选择使用 Gevent 这样的异步协程库。
Gevent 是一个高性能的 Python 并发库,它基于协程的概念,使用 Greenlet 来管理任务的执行。Gevent 提供了简洁、优雅的 API,能够轻松实现并发编程,适用于网络应用、爬虫、异步 IO 等场景。
在这篇文章中,我们将详细介绍 Gevent 的核心概念、工作原理、常用功能以及如何使用 Gevent 编写高效的异步程序。
⭕️宇宙起点
- 💯 Gevent 的核心概念
- 什么是协程?
- Gevent 的工作原理
- 为什么选择 Gevent?
- 📦 Gevent 的基本使用
- 安装 Gevent
- Greenlet 和协程
- Gevent 的猴子补丁
- Gevent 的常见功能
- 1. 并发网络请求
- 2. 使用队列进行协程间通信
- 3. 异步文件操作
- 4. 超时控制
- 🥇 性能优化建议
- 📥 下载地址
- 💬 结语
- 📒 参考文献
💯 Gevent 的核心概念
什么是协程?
协程(Coroutine) 是一种可以在执行过程中被挂起,并且在稍后某个时间点继续执行的函数。它与线程的区别在于,协程是由程序控制的,而线程的切换由操作系统调度。协程的执行模型非常轻量级,能够实现类似多线程的并发效果,却没有多线程的开销。
Gevent 的协程实现基于 Greenlet。Greenlet 是 Python 的一个轻量级协程库,它允许你在 Python 程序中手动切换任务,实现协程并发。Gevent 在此基础上进一步封装了异步 IO 和事件循环功能,使编写异步程序变得更加简单。
Gevent 的工作原理
Gevent 的核心是基于 事件循环 的协程调度。当一个协程(任务)遇到 IO 操作时,Gevent 会自动切换到其他协程执行,避免程序在等待 IO 的时候浪费资源。这种方式让程序可以同时处理多个任务,而不必阻塞在一个任务上。
Gevent 中的异步操作通过 monkey patching 实现。它可以将 Python 标准库中的一些阻塞 IO 操作(如 socket
、time.sleep
等)替换为非阻塞的协程版本,使得标准库可以与 Gevent 协同工作。
为什么选择 Gevent?
Gevent 适用于以下场景:
- 高并发网络应用:Gevent 非常适合开发需要处理大量并发请求的网络应用,如 Web 服务器、爬虫、聊天室等。
- 异步 IO 操作:需要高效处理 IO 操作(如文件读写、网络请求)的程序可以通过 Gevent 大大提升性能。
- 简化并发编程:与多线程和多进程相比,Gevent 的协程模型更简单,避免了线程间共享状态导致的复杂问题(如死锁、竞态条件)。
📦 Gevent 的基本使用
安装 Gevent
在使用 Gevent 之前,你需要安装它。可以通过 pip
进行安装:
pip install gevent
安装完成后,你就可以在项目中使用 Gevent 进行异步编程。
Greenlet 和协程
Gevent 使用 Greenlet 来表示一个轻量级的协程。每个 Greenlet 都是一个独立的任务,Gevent 会在任务之间进行调度。以下是使用 Greenlet 创建协程的基本示例:
import geventdef task(name):for i in range(3):print(f'Task {name} is running iteration {i}')gevent.sleep(1) # 模拟阻塞操作,使用 gevent.sleep 进行切换# 创建多个 Greenlet 并启动
gevent.joinall([gevent.spawn(task, 'A'),gevent.spawn(task, 'B'),gevent.spawn(task, 'C')
])
说明:
gevent.spawn
用于启动一个新的协程(Greenlet),第一个参数是要执行的函数,后面的参数是传递给函数的参数。gevent.sleep(1)
会让当前协程“睡眠”1秒,但它不会阻塞程序,而是会切换到其他任务执行。这使得程序在进行 IO 操作时不会被阻塞。
运行上述代码时,任务 A、B 和 C 会以并发的方式运行,而不是顺序执行。
Gevent 的猴子补丁
为了让标准库中的阻塞操作也能与 Gevent 一起工作,Gevent 提供了 monkey patching 功能。通过猴子补丁,Gevent 会将标准库中的阻塞函数替换为非阻塞版本。以下是如何使用猴子补丁的示例:
import gevent
from gevent import monkey
import time# 打开猴子补丁
monkey.patch_all()def blocking_task(name):print(f'Task {name} is starting...')time.sleep(2) # 被猴子补丁替换成 gevent.sleep,不再阻塞print(f'Task {name} is done!')# 创建协程并启动
gevent.joinall([gevent.spawn(blocking_task, 'A'),gevent.spawn(blocking_task, 'B')
])
说明:
monkey.patch_all()
是 Gevent 提供的一个功能,它会替换标准库中的阻塞函数,使其变为非阻塞的异步函数。通过这种方式,你可以继续使用标准库中的time.sleep
、socket
、requests
等阻塞操作,但它们不会阻塞程序,而是会自动切换协程。
运行上面的代码时,time.sleep(2)
不会阻塞任务 A 和 B,而是允许其他协程运行。
Gevent 的常见功能
1. 并发网络请求
Gevent 适合处理高并发网络请求,尤其是在爬虫等应用中非常有用。下面是一个示例,使用 Gevent 并发地进行多个 HTTP 请求。
import gevent
from gevent import monkey
import requests# 打开猴子补丁,替换 requests 的阻塞 IO
monkey.patch_all()def fetch_url(url):print(f'Start fetching {url}')response = requests.get(url)print(f'Finished fetching {url}: {len(response.content)} bytes')urls = ['https://www.python.org','https://www.gevent.org','https://www.github.com'
]# 并发抓取多个 URL
gevent.joinall([gevent.spawn(fetch_url, url) for url in urls])
说明:
monkey.patch_all()
替换了requests
库的阻塞操作,使得requests.get
在执行时不会阻塞主程序。gevent.spawn(fetch_url, url)
创建了一个新的协程,异步抓取 URL。
运行这个程序时,三个 URL 会被并发抓取,而不是顺序抓取,这大大提高了程序的效率。
2. 使用队列进行协程间通信
Gevent 提供了一个高效的队列(gevent.queue.Queue
),可以在协程之间传递数据。下面是一个简单的生产者-消费者模型:
import gevent
from gevent.queue import Queue# 创建队列
queue = Queue()def producer():for i in range(5):print(f'Producing item {i}')queue.put(i)gevent.sleep(1)def consumer():while True:item = queue.get() # 从队列中取出一个元素print(f'Consuming item {item}')# 创建生产者和消费者协程
gevent.joinall([gevent.spawn(producer),gevent.spawn(consumer)
])
说明:
gevent.queue.Queue
提供了线程安全的队列操作,适合在多个协程之间传递数据。- 生产者协程将数据放入队列,消费者协程从队列中取出数据。整个流程异步进行,不会阻塞主程序。
3. 异步文件操作
尽管 Gevent 主要用于网络 IO,但它也可以用来处理文件操作。以下示例展示了如何使用 Gevent 异步读取文件内容:
import gevent
import osdef read_file(file_path):print(f'Start reading {file_path}')with open(file_path, 'r') as f:data = f.read()print(f'Finished reading {file_path}: {len(data)} bytes')# 创建多个协程并读取不同的文件
gevent.joinall([gevent.spawn(read_file, 'file1.txt'),gevent.spawn(read_file, 'file2.txt')
])
说明:
- Gevent 适合与文件系统进行 IO 操作,能够在多个文件之间并发读取数据,而不会阻塞其他文件的读取。
4. 超时控制
Gevent 提供了对协程执行时间的超时控制,避免某些操作长时间阻塞程序。通过 gevent.Timeout
,你可以设置协程的超时时间:
import gevent
from gevent import Timeoutdef long_task():print('Task started...')gevent.sleep(5)print('Task completed!')# 设置超时时间为 2 秒
try:with Timeout(2):long_task()
except Timeout:print('Task timed out!')
说明:
Timeout
可以用来控制协程的最长执行时间。即使协程中使用了gevent.sleep
等异步操作,超时机制仍然生效,防止程序长时间等待。
🥇 性能优化建议
Gevent 本身是一个高效的异步并发库,但为了充分利用其性能,在使用时需要注意以下几点:
-
尽量避免长时间的 CPU 密集型任务:Gevent 适合处理 IO 密集型任务,如果你的程序中有大量 CPU 密集型计算,建议使用
gevent.threadpool
或者结合多进程处理。 -
适度使用协程数量:虽然 Gevent 可以支持大量并发协程,但过多的协程会导致上下文切换开销增加,建议根据实际场景合理控制协程数量。
-
猴子补丁的使用:
monkey.patch_all()
很有用,但也会影响一些库的行为。在大型项目中,仔细测试猴子补丁对第三方库的影响,确保兼容性。
📥 下载地址
Gevent 最新版 下载地址
💬 结语
Gevent 是一个非常强大的 Python 异步并发库,它简化了异步编程的复杂性,并提供了简洁高效的 API。通过 Gevent 的协程模型,开发者能够轻松编写高并发程序,而不必担心多线程编程中的复杂问题。
本文介绍了 Gevent 的核心概念、工作原理以及常用的功能特性,并通过实际代码示例展示了如何使用 Gevent 进行高效的异步编程。如果你正在开发需要处理大量并发操作的 Python 应用(如网络服务器、爬虫等),Gevent 无疑是一个非常不错的选择。
📒 参考文献
- Gevent 官网
- Gevent GitHub仓库
相关文章:

异步编程利器:深入解析 Python 异步并发库 Gevent
在现代 Python 应用开发中,并发编程 是提高程序性能、处理多个任务的关键手段之一。虽然 Python 有原生的多线程、多进程模块,但这些模块存在一些限制,比如全局解释器锁(GIL)会影响多线程程序的执行效率。此外…...

Python pyusb 使用指南【windows+linux】
前言:USB(通用串行总线)作为一种高度通用性的硬件接口,在诸多领域均有应用。在C中可以直接使用libusb库即可完成USB设备信息查询、USB设备监听、与USB设备控制端点、数据(同步、批量、中断)端点进行指令、数据交互等功能。python中…...

Xcode报错:The request was denied by service delegate (SBMainWorkspace)
Xcode报错:The request was denied by service delegate (SBMainWorkspace) 造成的原因: (1)新的M2芯片的Mac电脑 (2) 此电脑首次安装启动Xcode的应用程序 (3)此电脑未安装Rosetta 解决方法: (1)打开终端…...

面试系列-携程暑期实习一面
Java 基础 1、Java 中有哪些常见的数据结构? 图片来源于:JavaGuide Java集合框架图 Java 中常见的数据结构包含了 List、Set、Map、Queue,在回答的时候,只要把经常使用的数据结构给说出来即可,不需要全部记住 如下&…...

你以为建站很复杂?Baklib 5分钟解决你的痛点
你以为建站很复杂?Baklib 5分钟解决你的痛点! 在这个“快节奏”的互联网时代,想要快速搭建一个网站是很多人的刚需。今天我要介绍的,就是如何利用Baklib的CMS/Wiki模板,五分钟内让你的网站“横空出世”。废话不多说&am…...

极狐GitLab 17.4 重点功能解读【二】
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料: 极狐GitLab 官网极狐…...

LVS-DR实战案例,实现四层负载均衡
环境准备:三台虚拟机(NET模式或者桥接模式) 192.168.88.200 (web1)(安装nginx服务器作为测试) 192.168.88.201 (服务器)(用于部署lvs-dr) 192.168.88.202 (web2)…...

网游和3A类型游戏的CPU选择分析
目录 1. CPU性能基础 1.1 主频 1.2 三级缓存(L1、L2、L3缓存) 1.3 架构 1.4 单核与多核性能 2. 游戏类型分析 2.1 网游:以《永劫无间》为例 多核性能需求: 单核性能需求: CPU选择建议: 2.2 3A类…...

2024免费录屏软件的宝藏功能与实用技巧
在手机上操作很多时候为了记录方便都直接截图或者录屏,其实电脑也一样。现在面向电脑的录屏工具纷繁复杂,很容易让我们挑花了眼。今天这篇文章我将介绍几款免费的录屏软件为大家提供参考。 1.福昕录屏大师 链接达达:www.foxitsoftware.cn/R…...

linux---进程程序替换详解
提示:以下是本篇文章正文内容,下面案例可供参考 一、程序替换的原理 我们可以创建子进程通过程序替换,来执行不同的程序。程序替换不会重新创建子进程,我们通过程序替换函数,内核将磁盘中的可执行程序和数据加载到内存…...

笔试编程-百战成神——Day01
1.数字统计 题目来源:数字统计——牛客网 测试用例 算法原理 根据题目我们知道,首先要输出两个数字确定一个区间,寻找这个区间内数字中所有包含2的个数,比如12包含一个2,22包含两个2,以此类推,所以我们的…...

Qt+toml文件读写
Qttoml 使用 cpptoml 库示例Qt 项目中的代码示例 解释注意事项 在Qt中使用TOML(Tom’s Obvious, Minimal Language)格式的文件,可以通过第三方库来实现,例如 cpptoml。TOML是一种易于阅读和写入的配置文件格式,与JSON…...

浅谈C++之指针
一、基本介绍 在C中,指针是一种复杂的数据类型,它存储了另一个变量的内存地址。通过指针,程序可以直接访问和操作内存,这为编程提供了极大的灵活性和效率,但同时也增加了复杂性和潜在的错误风险。 二、指针的概念 指针…...

在虚幻引擎中实时显示帧率
引擎自带了显示帧率的功能 但是只能在编辑器中显示 , 在游戏发布后就没有了 , 所以我们要自己做一个 创建一个控件蓝图 创建画布和文本 , 修改文本 文本绑定函数 , 点击创建绑定 添加一个名为 FPS 的变量 格式化文本 用大括号把变量包起来 {FPS Int} FPS 然后转到事件图表…...

Apache Iceberg构建高性能数据湖
1. 概述 大数据时代的挑战 随着信息技术和互联网的迅猛发展,我们正处于一个数据爆炸的时代。企业和组织每天都在生成和收集海量的数据,这些数据来自于社交媒体、物联网设备、传感器、交易系统等各种来源。如何高效地存储、管理和分析这些庞大的数据集&…...

【图像压缩与重构】基于标准+改进BP神经网络
课题名称:基于标准改进BP神经网络的图像压缩与重构(带GUI) 代码获取方式(付费): 相关资料: 1. 代码注释 2.BP神经网络原理文档资料 3.图像压缩原理文档资料 程序实例截图: 1. 基于标准BP神经网络的图…...

函数式编程(以Python编程语言为例)介绍
函数式编程(以Python编程语言为例)介绍 何为函数式编程? 函数式编程(Functional Programming),不要误以为就是用函数编程。函数式编程确实涉及使用函数,但它不仅仅是“用函数编程”那么简单。 …...

银河麒麟操作系统中查看动态库函数的方法
银河麒麟操作系统中查看动态库函数的方法 1、查看单个动态库中的函数2、查找特定函数位于哪个动态库中 💖The Begin💖点点关注,收藏不迷路💖 在Linux系统,包括银河麒麟操作系统中,动态库(.so文件…...

开放麒麟openkylin
开源社区: openKylin: openKylin 社区的愿景是:在开源、自愿、平等和协作的基础上,由基础软硬件企业、非营利性组织、社团组织、高等院校、科研机构和个人开发者共同创立的一个开源社区。 下载地址: openKylin开源操作系统 安…...

用Python与OpenCV的实践:实时面部对称性分析
目录 思路分析 整体代码 效果展示 总结 在当今计算机视觉领域,人脸识别和分析技术得到了广泛应用。无论是安全验证、社交媒体应用,还是美学研究,人脸特征的提取和分析都是关键技术之一。在这篇博客中,我们将深入探讨一个有趣的…...

第三十三章 使用派生密钥令牌进行加密和签名 - 使用 DerivedKeyToken _进行加密(一)
文章目录 第三十三章 使用派生密钥令牌进行加密和签名 - 使用 <DerivedKeyToken> 第三十三章 使用派生密钥令牌进行加密和签名 - 使用 进行加密(一) 如果加密了任何安全标头元素,请将它们添加到 WS-Security 标头元素中。为此&#…...

Structure-Aware Transformer for Graph Representation Learning
Structure-Aware Transformer for Graph Representation Learning(ICML22) 摘要 Transformer 架构最近在图表示学习中受到越来越多的关注,因为它通过避免严格的结构归纳偏差而仅通过位置编码对图结构进行编码,自然地克服了图神经…...

滚动页面,el-table表头始终置顶
效果如下: 起始状态: 滚动后: 代码地址:代码地址-面包多...

Mac使用gradle编译springboot-2.7.x源码
1 开发环境: JDK8 ideaIU-2024.2.2 gradle-7.6.3 代理网络 2 下载springboot源码 代码仓库网址 git clone -b 2.7.x https://github.com/spring-projects/spring-boot.git3 安装gradle gradle下载网址 https://services.gradle.org/distributions/ 安装此文件指…...

MySQL --索引(下)
文章目录 6.索引操作6.1 创建主键索引6.2 创建唯一索引6.3 创建普通索引6.4 创建全文索引6.5 查询索引6.6 删除索引6.7 索引创建原则6.8 复合索引6.9 索引最左匹配原则6.10 索引覆盖 6.索引操作 6.1 创建主键索引 第一种方式: – 在创建表的时候,直接…...

选择寄宿学校,给自闭症孩子一个温暖的第二家
在寻找适合自闭症孩子成长的道路上,每一个家庭都充满了艰辛与希望。而广州市星贝育园康复中心,以其独特的全托寄宿制教育模式,为这些特殊的孩子提供了一个充满爱与关怀的“第二家”。在这里,孩子们不仅能够得到专业的康复训练&…...

大模型训练:K8s 环境中数千节点存储最佳实践
今天这篇博客来自全栈工程师朱唯唯,她在前不久举办的 KubeCon 中国大会上进行了该主题分享。 Kubernetes 已经成为事实的应用编排标准,越来越多的应用在不断的向云原生靠拢。与此同时,人工智能技术的迅速发展,尤其是大型语言模型&…...

【Linux学习】1-2 新建虚拟机ubuntu环境
1.双击打开VMware软件,点击“创建新的虚拟机”,在弹出的中选择“自定义(高级)” 2.点击下一步,自动识别ubuntu光盘映像文件,也可以点击“浏览”手动选择,点击下一步 3.设置名称及密码后…...

ftdi_sio驱动学习笔记 3 - 端口操作
目录 1. ftdi_port_probe 1.1 私有数据结构ftdi_private 1.2 特殊probe处理 1.3 确定FTDI设备类型 1.4 确定最大数据包大小 1.5 设置读取延迟时间 1.6 初始化GPIO 1.6.1 使能GPIO 1.6.2 添加到系统 1.6.2.1 设置GPIO控制器的基本信息 1.6.2.2 设置GPIO控制器的元信息…...

[leetcode]39_组合总和_给定数组且数组可重复
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的数字可以无限制重复被选取。说明: 所有数字(包括 target)都是正整数。 解集不能包含重复的组合…...