首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Python(29)Python生成器函数深度解析:asyncio事件循环的底层实现与异步编程实战

Python(29)Python生成器函数深度解析:asyncio事件循环的底层实现与异步编程实战

原创
作者头像
用户3672714
发布2025-07-13 10:56:57
发布2025-07-13 10:56:57
4300
举报

在这一篇中,我们将深入探讨 Python 生成器函数的工作原理,结合 asyncio 库实现异步编程。通过分析生成器函数的机制,我们将了解它们如何在 Python 中实现异步 I/O 操作,并通过实践示例深入解析。


1. 什么是生成器函数?

生成器函数是一种特殊类型的函数,它使用 yield 语句返回一个迭代器(iterator)。与普通的返回值不同,生成器函数返回的是一个 生成器对象,它可以在每次调用时逐个产生结果,而不会一次性将所有结果返回。

生成器函数的基本结构:

代码语言:javascript
复制
def simple_generator():    yield 1    yield 2    yield 3gen = simple_generator()print(next(gen))  # 输出 1print(next(gen))  # 输出 2print(next(gen))  # 输出 3php160 Bytes© 菜鸟-创作你的创作

生成器与普通函数的区别在于,生成器函数在每次 yield 时暂停执行,直到下一次调用 next() 时继续执行。


2. 生成器的工作机制

当调用生成器函数时,它并不会立即执行函数体,而是返回一个生成器对象。生成器对象可以使用 next() 函数或 for 循环逐个“拉取”值。

生成器函数的流程:

  • 暂停执行:每次遇到 yield,生成器函数就会暂停,返回一个值。
  • 恢复执行:当调用 next() 时,生成器函数会从上次 yield 停止的地方继续执行,直到遇到下一个 yield
  • 终止生成器:当生成器函数没有 yield 语句可执行时,它会抛出 StopIteration 异常,表示生成器已完成。

示例:

代码语言:javascript
复制
def countdown(n):    while n > 0:        yield n        n -= 1    print("Finished!")gen = countdown(5)for num in gen:    print(num)php139 Bytes© 菜鸟-创作你的创作

输出:

代码语言:javascript
复制
54321Finished!php19 Bytes© 菜鸟-创作你的创作

3. 生成器与异步编程的关系

在 Python 中,异步编程通常是通过 asyncio 库实现的,它的核心是事件循环和协程(coroutines)。生成器和协程有很多相似之处,它们都可以挂起和恢复执行。因此,理解生成器的工作机制有助于我们理解异步编程的底层实现。

asyncio 和异步编程概述

异步编程的关键是 事件循环,它负责调度和执行异步任务。通过将任务标记为“挂起”,异步程序可以在等待 I/O 操作时执行其他任务,这样可以避免阻塞和浪费时间。

Python 的异步编程是通过 协程(coroutines)和 asyncio 事件循环来实现的,asyncio 提供了用于并发执行 I/O 操作的工具。

  • 协程函数(coroutine function):使用 async def 声明。
  • 协程对象:协程函数返回的对象,它是可等待的(awaitable)。

基本示例:

代码语言:javascript
复制
import asyncioasync def hello_world():    print("Hello")    await asyncio.sleep(1)    print("World")# 事件循环运行协程asyncio.run(hello_world())php144 Bytes© 菜鸟-创作你的创作

输出:

代码语言:javascript
复制
Hello(等待 1 秒)Worldphp20 Bytes© 菜鸟-创作你的创作

在上面的例子中,await 会暂停协程的执行,直到 asyncio.sleep(1) 完成,然后继续执行。这是异步编程的核心:在等待某个操作(如网络请求、磁盘 I/O 等)时,可以去执行其他任务。


4. 生成器与异步编程的联系

在旧版的 Python 中,asyncio 事件循环是基于生成器实现的,通过使用 yield 控制异步任务的挂起和恢复。通过这种方式,生成器函数可以像协程一样异步执行。

使用生成器实现异步任务

代码语言:javascript
复制
import asyncio# 自定义事件循环def my_sleep(seconds):    print(f"Sleeping for {seconds} seconds...")    yield asyncio.sleep(seconds)    print(f"Woke up after {seconds} seconds")async def main():    # 异步调用    await asyncio.gather(        my_sleep(2),        my_sleep(3)    )# 事件循环执行asyncio.run(main())php308 Bytes© 菜鸟-创作你的创作

注意:在 Python 3.5 之后,async def 和 await 语法被引入,提供了更加简洁和高效的方式来实现异步编程。yield 不再用于异步操作,但它仍然是理解协程工作原理的关键。


5. 生成器与 asyncio 的结合:异步生成器

在 Python 3.6 及之后的版本,Python 引入了 异步生成器async def 与 yield 的结合)。这种方式允许你在生成器中使用异步操作(如 await),从而实现更加复杂的异步行为。

异步生成器的工作方式

异步生成器函数与普通生成器函数类似,只是它们是异步的,使用 async def 声明,并且 yield 语句会在协程中等待某些异步操作。

示例:异步生成器

代码语言:javascript
复制
import asyncioasync def async_countdown(n):    while n > 0:        print(f"Counting down: {n}")        await asyncio.sleep(1)  # 模拟异步操作        yield n        n -= 1    print("Finished!")async def main():    async for number in async_countdown(5):        print(f"Got number: {number}")# 启动事件循环asyncio.run(main())php326 Bytes© 菜鸟-创作你的创作

输出:

代码语言:javascript
复制
Counting down: 5(等待 1 秒)Got number: 5Counting down: 4(等待 1 秒)Got number: 4Counting down: 3(等待 1 秒)Got number: 3Counting down: 2(等待 1 秒)Got number: 2Counting down: 1(等待 1 秒)Got number: 1Finished!php209 Bytes© 菜鸟-创作你的创作

解释:

  • async def async_countdown(n) 是一个异步生成器。
  • await asyncio.sleep(1) 是一个异步操作,模拟耗时任务。
  • async for number in async_countdown(5) 用来异步迭代生成器的值。

6. asyncio 事件循环的底层实现

asyncio 提供了一个事件循环,负责调度和执行异步任务。其底层实现与生成器类似,使用了协程和生成器的概念。事件循环会负责监控所有正在运行的协程,直到它们完成。

事件循环的基本流程:

  1. 创建任务:任务是协程的封装,事件循环通过调度任务来运行协程。
  2. 挂起任务:当协程遇到 await 时,事件循环会挂起该任务,直到 await 的结果返回。
  3. 恢复任务:当某个操作完成时,事件循环会恢复对应的协程任务,继续执行。

示例:手动控制事件循环

代码语言:javascript
复制
import asyncioasync def task_1():    print("Task 1 started")    await asyncio.sleep(1)    print("Task 1 finished")async def task_2():    print("Task 2 started")    await asyncio.sleep(2)    print("Task 2 finished")async def main():    task1 = asyncio.create_task(task_1())    task2 = asyncio.create_task(task_2())    await task1    await task2# 启动事件循环asyncio.run(main())php390 Bytes© 菜鸟-创作你的创作

输出:

代码语言:javascript
复制
Task 1 startedTask 2 startedTask 1 finishedTask 2 finishedphp61 Bytes© 菜鸟-创作你的创作

在这里,两个任务是并发执行的,task_1 的执行时间较短,而 task_2 需要 2 秒。事件循环调度任务时,确保 task_1 和 task_2 在等待时不会阻塞其他任务。


7. 总结

  • 生成器函数:使用 yield 按需生成数据,可以逐步生成和返回数据,而不是一次性返回所有数据。
  • 异步编程:通过 asyncio 库和协程实现,避免阻塞,提高程序的执行效率,特别是在 I/O 密集型任务中。
  • 异步生成器:结合了生成器和异步编程,可以在生成数据的同时执行异步操作。
  • 事件循环asyncio 的核心,通过调度和执行协程,保证异步任务的执行顺序。

通过理解生成器的原理和异步编程的机制,开发者可以有效

地管理 I/O 操作,提升程序的性能。https://www.52runoob.com/archives/3457

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 什么是生成器函数?
    • 生成器函数的基本结构:
  • 2. 生成器的工作机制
    • 生成器函数的流程:
    • 示例:
  • 3. 生成器与异步编程的关系
    • asyncio 和异步编程概述
    • 基本示例:
    • 输出:
  • 4. 生成器与异步编程的联系
    • 使用生成器实现异步任务
  • 5. 生成器与 asyncio 的结合:异步生成器
    • 异步生成器的工作方式
    • 示例:异步生成器
    • 解释:
  • 6. asyncio 事件循环的底层实现
    • 事件循环的基本流程:
    • 示例:手动控制事件循环
    • 输出:
  • 7. 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档