Python 协程(Coroutine)的使用

在 Python 中,协程Coroutine)是一种比线程更轻量级的并发执行方式,它允许在程序中暂停执行某个任务并切换到其他任务,从而提高程序的效率,尤其适用于 I/O 密集型任务。

协程的核心概念:

  • 协程是可挂起的函数,它能够在执行过程中暂停(挂起),并且能够在之后恢复执行。
  • 协程是 基于事件循环 和 异步 I/O 模型来实现并发的,而不是通过多线程或多进程。
  • 协程通常与 async 和 await 关键字一起使用。

1. 协程的定义

在 Python 中,协程是通过 async def 关键字定义的。这种函数定义会返回一个协程对象,而不是直接执行函数的代码。

import asyncio

# 定义一个协程
async def my_coroutine():
    print("协程开始")
    await asyncio.sleep(1)  # 模拟耗时操作,非阻塞
    print("协程结束")

在上面的例子中:

  • async def 定义了一个异步函数 my_coroutine。
  • await asyncio.sleep(1) 是一个非阻塞的 sleep,它让协程等待 1 秒钟,不会阻塞整个程序。

2. await 关键字

await 是协程中用于暂停执行当前协程的关键字。它会等待另一个协程或异步操作完成,并且在等待的过程中可以执行其他任务(如其他协程)。

async def example():
    print("开始等待")
    await asyncio.sleep(2)  # 暂停 2 秒
    print("等待结束")

3. 事件循环(Event Loop)

Python 的异步编程依赖于事件循环(event loop)。事件循环是一个不断轮询的循环,负责管理和调度任务。协程通过事件循环进行调度,当一个协程被 await 挂起时,事件循环可以去执行其他的协程。

4. 运行协程

协程并不会立即执行,必须通过 asyncio 或类似的异步运行机制来运行它。最常见的做法是使用 asyncio.run() 来启动协程。

# 运行协程
asyncio.run(my_coroutine())

5. 多个协程并发执行

可以同时运行多个协程,通过 asyncio.gather() 来并发执行多个协程。

async def task1():
    print("任务 1 开始")
    await asyncio.sleep(1)
    print("任务 1 结束")

async def task2():
    print("任务 2 开始")
    await asyncio.sleep(2)
    print("任务 2 结束")

async def main():
    # 并发运行任务 1 和 任务 2
    await asyncio.gather(task1(), task2())

# 运行主协程
asyncio.run(main())

6. asyncio.run() 的作用

asyncio.run() 用于启动一个新的事件循环并运行给定的协程。在事件循环完成后,asyncio.run() 会关闭事件循环并返回。具体而言,asyncio.run() 会执行以下操作:

  • 创建一个新的事件循环。
  • 在该事件循环中运行传入的协程,直到协程执行完成。
  • 关闭事件循环。

为什么说 asyncio.run() 是阻塞的?
当你调用 asyncio.run() 时,它会启动并运行一个事件循环,直到事件循环中的所有任务完成。这个过程是 阻塞的,也就是说,asyncio.run() 会等到传入的协程执行完毕后才会返回。

import asyncio

async def my_coroutine():
    print("协程开始")
    await asyncio.sleep(1)
    print("协程结束")

# 事件循环在这里会被阻塞,直到协程执行完毕
asyncio.run(my_coroutine())
print("主程序结束")

输出:

协程开始
协程结束
主程序结束

7. 协程的优势

  • 轻量级:协程在内存和执行开销上比线程更轻量。相比线程,它们不需要上下文切换和线程间通信,因此可以高效处理大量并发任务。
  • 异步 I/O 操作:协程特别适合处理 I/O 密集型任务,例如网络请求、磁盘操作、数据库查询等。这些任务通常涉及等待外部资源,协程可以在等待过程中执行其他任务,而不像传统的同步方式那样阻塞整个程序。
  • 无需多线程:协程通过事件循环机制来实现并发,不需要额外的线程管理,避免了线程创建和上下文切换的开销。

8. 协程的与线程的对比

  • 线程:每个线程都有自己的栈内存,操作系统需要为其分配资源(如线程上下文)。线程之间的切换是由操作系统进行的,通常会有比较高的性能开销。
  • 协程:协程比线程更加轻量,内存消耗较小,且协程之间的切换由 Python 解释器管理,因此切换开销小很多。协程适用于 I/O 密集型任务,而线程适用于 CPU 密集型任务。

9. 协程的应用场景

  • 网络请求:通过协程,可以在等待网络响应时执行其他任务,从而提高效率。
    数据库查询:在数据库操作过程中,可以使用协程执行其他查询。
  • 爬虫:爬虫程序通常需要等待 HTTP 请求的响应,协程可以在等待时并发处理其他请求。
    GUI 程序:在一些 GUI 程序中,可以使用协程在后台执行耗时任务,同时保持界面响应。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ta叫我小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值