Python—协程(Coroutine)

Python—协程(Coroutine)

协程(Coroutine)是 Python 中一种比线程更加轻量级的并发机制,它允许你在一个线程中执行多个任务。相比于传统的线程或进程,协程更加高效,因为它们不需要进行上下文切换,而且能以更低的内存消耗实现并发执行。

在 Python 中,协程通常是通过 asyncio 库来实现的,使用 asyncawait 关键字来定义和管理协程。

本文将详细介绍 Python 中的协程概念,并通过代码示例、图解和详细说明帮助你更容易理解和使用协程。

一、协程的基本概念

协程是比线程更轻量的并发单元,它可以暂停执行并在需要时恢复。通过协程,多个任务可以在同一个线程中并发执行,而无需创建多个线程或进程,从而避免了线程上下文切换的高开销。

与传统的函数不同,协程函数是通过 async def 来定义的,而协程的执行可以通过 await 来挂起。

协程的优点

  1. 高效:协程基于事件循环(event loop),无需上下文切换,避免了线程和进程的开销。
  2. 轻量级:协程占用的内存少,可以在同一个线程中同时运行大量任务。
  3. 非阻塞:当协程执行到 I/O 操作时,可以挂起当前协程,执行其他任务,避免了传统线程中的阻塞等待问题。

二、协程的基础用法

1. 使用 async def 定义协程函数

一个协程函数是通过 async def 关键字来定义的。与普通函数不同,协程函数在执行时并不会立即执行,而是返回一个协程对象。

import asyncio

# 定义一个简单的协程函数
async def my_coroutine():
    print("Start of coroutine")
    await asyncio.sleep(2)  # 模拟IO操作,挂起当前协程
    print("End of coroutine")

# 调用协程函数
asyncio.run(my_coroutine())

代码解析:

  1. async def my_coroutine() 定义了一个协程函数 my_coroutine
  2. await asyncio.sleep(2) 表示挂起当前协程2秒钟,模拟一个 I/O 操作。
  3. asyncio.run(my_coroutine()) 运行协程 my_coroutine(),并启动事件循环。

输出:

Start of coroutine
# 稍等2秒
End of coroutine

2. await 关键字

await 关键字用于等待另一个协程执行完毕。在执行 await 语句时,当前协程会被挂起,控制权交给事件循环。直到 await 后的协程完成时,当前协程才会继续执行。

3. 协程中的 I/O 操作

协程的一个重要特点是它能够在执行 I/O 操作(如网络请求、文件读写等)时挂起当前任务,避免阻塞其他任务。通过这种方式,可以在单线程中处理多个任务。

import asyncio

# 模拟网络请求
async def fetch_data(url):
    print(f"Fetching data from {url}...")
    await asyncio.sleep(2)  # 模拟网络请求的延时
    print(f"Fetched data from {url}")

async def main():
    # 启动多个协程同时执行
    await asyncio.gather(
        fetch_data("http://example.com"),
        fetch_data("http://example.org"),
        fetch_data("http://example.net")
    )

asyncio.run(main())

代码解析:

  1. fetch_data 是一个协程函数,模拟从指定 URL 获取数据。
  2. main 协程中,使用 asyncio.gather 同时启动多个协程,这些协程会并发执行。
  3. 每个协程在等待 asyncio.sleep(2) 时,事件循环会切换到其他协程,避免阻塞。

输出:

Fetching data from http://example.com...
Fetching data from http://example.org...
Fetching data from http://example.net...
# 等待2秒
Fetched data from http://example.com
Fetched data from http://example.org
Fetched data from http://example.net

三、协程与线程/进程的比较

特性协程线程进程
内存占用极低,所有协程共享相同的内存空间每个线程都有独立的栈空间每个进程都有独立的内存空间
上下文切换无需上下文切换,轻量级上下文切换开销较大上下文切换开销较大
并发性适用于 I/O 密集型任务适用于 CPU 密集型任务适用于计算密集型任务
易用性简单,使用 async/await 控制流需要多线程编程技巧需要多进程编程技巧
适用场景网络爬虫、Web 开发、I/O 操作数据分析、计算密集型任务需要隔离的计算任务

从表格中可以看出,协程适用于 I/O 密集型任务,能够高效地处理大量并发任务,而线程和进程则更适用于计算密集型任务。

四、图解协程的执行流程

以下是一个简单的协程执行流程的图解:

+------------------+             +------------------+
|    Coroutine 1   |    ---->    |   Await/IO Block  |
+------------------+             +------------------+
         |                           |
         v                           v
+------------------+             +------------------+
|    Coroutine 2   |    ---->    |   Await/IO Block  |
+------------------+             +------------------+
         |                           |
         v                           v
+------------------+             +------------------+
|    Coroutine 3   |    ---->    |   Await/IO Block  |
+------------------+             +------------------+
         |                           |
         v                           v
+-------------------+            +-------------------+
|   Event Loop      | <--------> |   Schedule Next   |
+-------------------+            +-------------------+

协程执行流程:

  1. 协程开始执行,遇到 await 时会挂起,控制权交回事件循环。
  2. 事件循环会调度其他协程继续执行。
  3. 等待的协程完成 I/O 操作后,事件循环会恢复其执行,继续后续操作。

五、总结

Python 协程是一个非常强大的并发工具,特别适用于 I/O 密集型的任务。在学习协程时,理解 async defawait 的用法是关键。通过协程,我们可以轻松实现并发任务,并且能够大大提高效率,尤其是在处理大量的网络请求或数据库操作时。

本篇文章重点总结:

  1. 协程的定义:使用 async def 定义,使用 await 挂起执行。
  2. I/O 操作的优化:通过协程优化 I/O 密集型任务。
  3. 事件循环:事件循环管理多个协程的执行,确保高效的资源利用。
  4. 协程 vs 线程 vs 进程:协程相较于线程和进程在并发处理 I/O 操作时具有显著优势。

通过本篇教程,你应该能够掌握 Python 协程的基本概念及其应用,灵活使用 asyncio 进行高效并发编程。

最后修改于:2024年11月27日 21:15

评论已关闭

推荐阅读

DDPG 模型解析,附Pytorch完整代码
2024年11月24日
DQN 模型解析,附Pytorch完整代码
2024年11月24日
AIGC实战——Transformer模型
2024年12月01日
Socket TCP 和 UDP 编程基础(Python)
2024年11月30日
python , tcp , udp
如何使用 ChatGPT 进行学术润色?你需要这些指令
2024年12月01日
AI
最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)
2024年11月24日
ChatGPT 和 DALL·E 2 配合生成故事绘本
2024年12月01日
omegaconf,一个超强的 Python 库!
2024年11月24日
【视觉AIGC识别】误差特征、人脸伪造检测、其他类型假图检测
2024年12月01日
[超级详细]如何在深度学习训练模型过程中使用 GPU 加速
2024年11月29日
Python 物理引擎pymunk最完整教程
2024年11月27日
MediaPipe 人体姿态与手指关键点检测教程
2024年11月27日
深入了解 Taipy:Python 打造 Web 应用的全面教程
2024年11月26日
基于Transformer的时间序列预测模型
2024年11月25日
Python在金融大数据分析中的AI应用(股价分析、量化交易)实战
2024年11月25日
AIGC Gradio系列学习教程之Components
2024年12月01日
Python3 `asyncio` — 异步 I/O,事件循环和并发工具
2024年11月30日
llama-factory SFT系列教程:大模型在自定义数据集 LoRA 训练与部署
2024年12月01日
Python 多线程和多进程用法
2024年11月24日
Python socket详解,全网最全教程
2024年11月27日