博客
关于我
Python asyncio库的学习和使用
阅读量:798 次
发布时间:2023-03-05

本文共 2259 字,大约阅读时间需要 7 分钟。

Python 异步编程:理解 async 和 await 的执行顺序

在编写爬虫脚本时,经常会遇到性能瓶颈问题。传统的 requests + 多线程/多进程 方法虽然能够提高并发度,但由于其阻塞性,往往导致资源消耗过大,尤其是在等待网页响应和处理数据时。为了应对这一问题,Python 3.4 及及以上版本引入了异步 IO 编程模型,通过 asyncawait 关键字实现非阻塞式操作。

understanding async 和 await 的执行顺序

在理解 asyncawait 之前,首先需要明确阻塞调用和非阻塞调用之间的区别:

  • 阻塞调用:调用结果返回之前,当前线程会被挂起,无法执行其他任务,直到结果返回。
  • 非阻塞调用:调用结果返回后,立即返回给调用者,执行程序的其他部分。
  • 在 Python 中,asyncawait 是实现异步 IO 的关键工具。从 Python 3.5 开始,asyncawait 取代了之前的 @asyncio.coroutineyield from,使得代码更加直观。

    一个简单的示例说明

    以下是官方示例代码,用于说明 asyncawait 的执行顺序:

    import asyncioasync def compute(x, y):    print("Compute %s + %s ..." % (x, y))    await asyncio.sleep(1.0)  # 非阻塞式睡眠    return x + yasync def print_sum(x, y):    result = await compute(x, y)    print("%s + %s = %s" % (x, y, result))loop = asyncio.get_event_loop()loop.run_until_complete(print_sum(1, 2))loop.close()

    传统方式执行顺序

    如果没有使用 asyncawait,程序的执行流程是:

  • 调用 print_sum(1, 2)
  • 将参数传递给 compute(1, 2)
  • 执行 print("Compute 1 + 2 ...")
  • 睡眠 1 秒。
  • 返回结果 3
  • 打印 "1 + 2 = 3"
  • 程序结束。
  • 异步方式执行顺序

    使用 asyncawait 后,执行流程如下:

  • 调用 print_sum(1, 2)
  • 非阻塞式执行 compute(1, 2),即同时启动 compute
  • 执行 print("Compute 1 + 2 ...") 并等待 1 秒。
  • 返回结果 3
  • 执行 print("1 + 2 = 3")
  • 事件循环与任务

    在异步编程中,事件循环(event loop)扮演着核心角色。它负责管理和调度任务(tasks),确保每个任务按正确顺序执行。

    • event loop:负责检测和处理 I/O 事件。
    • tasks:异步操作的执行单元,由 asyncio.Futureasyncio.Task 实现。

    在上述代码中,get_event_loop() 获取事件循环,run_until_complete() 方法运行指定的协程对象,并返回控制权。

    优化后的代码示例

    为了更直观地理解异步执行顺序,可以稍作修改:

    import asyncioasync def compute(x, y):    print("Compute %s + %s ..." % (x, y))    await asyncio.sleep(10.0)  # 非阻塞式睡眠    return x + yasync def print_sum(x, y):    result = await compute(x, y)    print("%s + %s = %s" % (x, y, result))loop = asyncio.get_event_loop()tasks = [print_sum(1, 2), print_sum(3, 4)]loop.run_until_complete(asyncio.wait(tasks))loop.close()

    执行结果解析

    在此优化后的代码中,sleep(10.0) 被修改为更长的睡眠时间,以更直观地观察任务执行顺序:

  • print_sum(3, 4):首先提交任务,立即返回,开始计算 3 + 4
  • sleep(10.0):非阻塞式执行,等待 10 秒。
  • print_sum(1, 2):立即提交任务,开始计算 1 + 2
  • sleep(10.0):非阻塞式执行,等待 10 秒。
  • 最终结果显示:

    Compute 3 + 4 ...Compute 1 + 2 ...暂停 10 秒左右3 + 4 = 71 + 2 = 3

    从执行结果可以看出,事件循环会先完成所有已提交的任务,并等待所有任务完成后才继续后续操作。

    总结

    通过以上示例,可以清晰地看到 asyncawait 在异步编程中的重要作用。它们允许在不阻塞主线程的情况下,非顺序地执行任务,显著提升了爬虫等 I/O 驱动型任务的性能表现。理解事件循环和任务的执行机制,是掌握异步编程的关键。

    如果需要更深入的理解,可以参考相关的技术文档或博客。例如,了解 asyncio.Future 的实现机制,以及如何在实际应用中高效地利用异步编程。

    转载地址:http://jvafk.baihongyu.com/

    你可能感兴趣的文章
    PyCharm点击设置没反应,无法进行设置
    查看>>
    pycharm的安装配置和简单使用
    查看>>
    pycharm的环境管理-ChatGPT4o作答
    查看>>
    pycharm社区版不能使用conda
    查看>>
    Pycharm终端中conda无法切换到虚拟环境的解决方法(两种方案)
    查看>>
    pycharm连接sqlite
    查看>>
    Pycharm那些隐藏的实用小技巧,yyds!
    查看>>
    PyCharm配置SSH和SFTP远程连接服务器
    查看>>
    Pycharm隐藏的实用小技巧!建议收藏
    查看>>
    PyChord 项目常见问题解决方案
    查看>>
    pydoc使用
    查看>>
    pyechart
    查看>>
    pyecharts中管理工具按钮以及修改图表主题
    查看>>
    pyechart值域区间
    查看>>
    pyest+appium实现APP自动化测试,思路全总结在这里
    查看>>
    Pygame
    查看>>
    Pygame 围绕轴旋转立方体
    查看>>
    Pygame 的详细介绍-ChatGPT4o作答
    查看>>
    Pygame 窗口几秒钟后没有响应
    查看>>
    Pygame.display.togling_fulcreen()不起作用
    查看>>