0

0

Python中的协程(Coroutine)和异步编程是如何工作的?

夢幻星辰

夢幻星辰

发布时间:2025-09-06 14:32:01

|

862人浏览过

|

来源于php中文网

原创

答案:调试和优化Python异步代码需理解事件循环、使用asyncio内置工具、避免阻塞调用、合理管理任务与异常。具体包括:利用asyncio.run()和日志监控协程执行;用asyncio.create_task()并发运行任务并捕获异常;避免在协程中调用time.sleep()等阻塞函数,改用asyncio.sleep();使用异步数据库和HTTP客户端(如asyncpg、httpx);通过asyncio.gather()并发等待多个协程;分析性能瓶颈时结合cProfile和aiomonitor等工具,确保I/O密集型操作不阻塞事件循环,从而提升整体吞吐量和响应速度。

python中的协程(coroutine)和异步编程是如何工作的?

Python中的协程和异步编程,本质上是一种实现并发的非阻塞I/O模型。它通过在等待I/O操作(比如网络请求、文件读写)完成时,将CPU时间让给其他任务,从而提高程序的效率和响应速度。这不是真正的并行执行,而是一种协作式多任务处理,让单个线程能够“同时”处理多个任务,避免了传统阻塞式I/O造成的资源浪费。

当我第一次接触Python的异步编程时,它给我带来了不小的冲击。那种“明明是单线程,却能高效处理大量并发请求”的感觉,一开始确实有点反直觉。但深入理解后,你会发现它的核心思想其实非常优雅:让程序在等待外部事件时,不再傻傻地空耗资源,而是主动切换去处理其他有意义的事情。

Python实现协程和异步编程的关键在于

async
await
这两个关键字,它们是
asyncio
库的语法糖。
async def
用来定义一个协程函数,这意味着这个函数在执行时可以被暂停和恢复。而
await
则是一个关键的暂停点。当你在一个协程函数内部遇到一个
await
表达式时,它会暂停当前协程的执行,将控制权交还给事件循环(Event Loop)。事件循环会去检查是否有其他协程已经准备好运行,或者是否有之前暂停的I/O操作已经完成。一旦
await
等待的那个操作完成,事件循环就会把控制权还给原来的协程,让它从暂停的地方继续执行。

这个事件循环,可以看作是异步编程的“心脏”。它不断地循环,管理着所有注册的协程任务,调度它们的执行顺序。当一个网络请求发出后,

await
会告诉事件循环:“嘿,我暂时没事干了,等数据回来再叫我。”事件循环收到信号,不会傻等,而是立即去运行其他协程。等到网络数据真的回来了,事件循环会通知之前暂停的协程:“你的数据到了,可以继续了!”这种非阻塞的工作模式,极大地提升了处理高并发I/O密集型任务的能力。

立即学习Python免费学习笔记(深入)”;

举个简单的例子,设想你正在煮饭(一个任务),同时还在等快递(另一个I/O任务)。传统同步编程就像你必须一直盯着锅,直到饭熟了才去门口等快递。而异步编程则是你把饭放锅里,设定好时间,然后就去门口等快递。如果快递来了,你处理完,再回来看饭。如果快递没来,饭也还没熟,你可能就去刷个手机(处理其他任务)。这种效率上的差异,在面对成千上万个并发请求时,就显得尤为重要。它避免了为每个请求都创建一个新的线程或进程所带来的巨大开销。

asyncio
库提供了一整套工具来构建异步应用,包括创建和管理任务(
asyncio.create_task
)、运行事件循环(
asyncio.run
)、以及各种异步原语,比如锁、队列、信号量等等。理解这些机制,是掌握Python异步编程的基石。它不是魔法,而是一种精巧的协作式调度艺术。

协程与传统多线程/多进程有哪些本质区别

这个问题经常被问到,因为它触及了并发编程的核心。在我看来,协程、多线程和多进程虽然都能实现并发,但它们在“如何实现”和“代价几何”上,简直是天壤之别。

根本区别在于调度方式和资源开销:

  1. 调度方式:

    ShopEx助理
    ShopEx助理

    一个类似淘宝助理、ebay助理的客户端程序,用来方便的在本地处理商店数据,并能够在本地商店、网上商店和第三方平台之间实现数据上传下载功能的工具。功能说明如下:1.连接本地商店:您可以使用ShopEx助理连接一个本地安装的商店系统,这样就可以使用助理对本地商店的商品数据进行编辑等操作,并且数据也将存放在本地商店数据库中。默认是选择“本地未安装商店”,本地还未安

    下载
    • 多进程: 操作系统级别调度。每个进程有独立的内存空间,互不干扰。操作系统负责在不同进程间切换,这种切换开销大,但隔离性最好。
    • 多线程: 操作系统或运行时调度。线程共享进程的内存空间,但每个线程有自己的栈。线程切换比进程轻量,但仍然需要操作系统的干预。而且,由于共享内存,数据同步(锁、信号量等)是必须面对的复杂问题,容易引入竞态条件和死锁。
    • 协程: 用户态(或称协作式)调度。协程在单个线程内运行,由程序自身(通过事件循环)进行调度。当一个协程遇到
      await
      时,它会主动放弃CPU,将控制权交给事件循环,让事件循环去执行其他协程。这种切换非常轻量,因为不涉及操作系统上下文切换,纯粹是函数栈的切换。
  2. 资源开销:

    • 多进程: 创建和销毁进程的开销最大,每个进程需要独立的内存空间,资源消耗高。
    • 多线程: 创建和销毁线程的开销比进程小,但每个线程仍需一定的栈空间和操作系统资源。线程数量过多时,会带来显著的调度开销(上下文切换)。
    • 协程: 开销最小。协程本质上只是一个函数调用栈帧的保存和恢复,不涉及操作系统的线程或进程创建。一个线程可以运行成千上万个协程,而不会像线程那样迅速耗尽资源。

适用场景:

  • 多进程: CPU密集型任务,需要利用多核CPU的计算能力。因为Python的GIL(全局解释器锁)限制了单个Python进程在同一时刻只能有一个线程执行Python字节码,所以对于纯计算任务,多进程是突破GIL限制的有效方式。
  • 多线程: I/O密集型任务,但由于GIL的存在,其优势不如其他语言明显。在Python中,多线程通常用于处理阻塞I/O操作,当一个线程在等待I/O时,GIL会被释放,其他线程可以执行Python代码。然而,如果任务不是纯粹的I/O阻塞,或者涉及大量Python代码执行,GIL会成为性能瓶颈。
  • 协程(异步编程): 极其适合I/O密集型任务,尤其是高并发的网络服务。它在单个线程内通过非阻塞I/O和协作式调度,高效地处理大量并发连接,而无需承担多线程/多进程的额外开销和复杂性。它不会被GIL限制,因为所有协程都在同一个线程中运行。

从我的经验来看,如果你需要处理大量的并发网络请求(比如构建一个高性能的Web服务器或爬虫),异步编程几乎是Python的首选。而如果你需要进行大规模的科学计算或数据处理,并且想充分利用多核CPU,那么

multiprocessing
模块会是你的好伙伴。理解它们各自的优缺点和适用场景,才能做出最合适的架构选择。

在实际项目中,何时应该考虑使用Python异步编程?

在我的开发实践中,选择异步编程通常是出于对性能和资源效率的考量,尤其是在处理特定类型的任务时。并不是所有项目都适合异步,但一旦遇到它的“甜蜜点”,效果会非常显著。

你应当考虑使用Python异步编程的场景:

  1. 高并发网络服务: 这是异步编程最典型的应用场景。例如,构建一个需要同时处理数千甚至数万个客户端连接的Web服务器(如使用
    FastAPI
    Sanic
    )、API网关、聊天服务器、或者实时数据处理服务。在这些场景下,大部分时间都在等待网络I/O(请求的发送和响应的接收),而不是进行CPU计算。异步编程能够让单个线程高效地管理这些并发连接,避免了为每个连接创建线程或进程所带来的巨大开销和上下文切换的性能损耗。
  2. Web爬虫/数据抓取: 当你需要从大量网站并行抓取数据时,异步编程能大幅提高效率。传统同步爬虫一个接一个地请求网页,效率低下。而异步爬虫可以同时发起数百个HTTP请求,并在等待响应时切换到其他任务,大大缩短了总抓取时间。像
    httpx
    这样的异步HTTP客户端,配合
    asyncio
    ,能让你轻松构建高性能爬虫。
  3. 数据库操作(异步驱动): 如果你的应用是I/O密集型的,并且数据库操作是性能瓶颈,那么使用支持异步的数据库驱动(如
    asyncpg
    for PostgreSQL,
    aiomysql
    for MySQL)可以显著提升性能。当一个数据库查询正在执行时,应用程序可以切换到处理其他请求,而不是阻塞等待数据库返回结果。
  4. 消息队列消费者/生产者: 在处理消息队列(如Kafka, RabbitMQ)时,如果需要高吞吐量地消费或生产消息,异步编程可以帮助你构建响应更快的消费者和生产者。
  5. 长时间运行的I/O操作: 任何需要等待外部资源响应的长时间操作,比如文件读写、调用外部API、等待硬件响应等,都可能从异步编程中受益。

一些需要注意的地方:

  • 生态系统支持: 异步编程需要整个生态系统的支持。如果你的所有依赖库都是同步的,那么引入异步的成本会很高,因为你可能需要自己封装同步库,或者等待异步版本的出现。幸运的是,现在越来越多的库提供了异步API。
  • 代码复杂性: 异步代码的编写和调试有时会比同步代码更复杂,尤其是对于初学者。你需要理解事件循环、任务调度、以及如何正确处理异步异常等概念。
  • CPU密集型任务不适用: 如果你的任务主要是CPU计算,而不是等待I/O,那么异步编程并不会带来性能提升,甚至可能因为额外的调度开销而略微下降。这种情况下,多进程通常是更好的选择。

总的来说,当你发现应用程序的性能瓶颈在于等待外部I/O,并且需要处理大量的并发连接时,异步编程就是你的利器。它能让你用更少的资源,达到更高的吞吐量。

如何调试和优化Python异步代码以提高性能?

调试和优化异步

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

668

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

247

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

281

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

515

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

256

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

386

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

532

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

602

2023.08.14

Python 自然语言处理(NLP)基础与实战
Python 自然语言处理(NLP)基础与实战

本专题系统讲解 Python 在自然语言处理(NLP)领域的基础方法与实战应用,涵盖文本预处理(分词、去停用词)、词性标注、命名实体识别、关键词提取、情感分析,以及常用 NLP 库(NLTK、spaCy)的核心用法。通过真实文本案例,帮助学习者掌握 使用 Python 进行文本分析与语言数据处理的完整流程,适用于内容分析、舆情监测与智能文本应用场景。

10

2026.01.27

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

相关下载

更多

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.3万人学习

Node.js 教程
Node.js 教程

共57课时 | 9.5万人学习

CSS3 教程
CSS3 教程

共18课时 | 4.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号