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

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序
一、开发环境准备 工具安装: 下载安装DevEco Studio 4.0(支持HarmonyOS 5)配置HarmonyOS SDK 5.0确保Node.js版本≥14 项目初始化: ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...