异步编程

介绍#

异步编程(Asynchronous Programming)是一种程序设计范式,旨在处理耗时操作(如 I/O 操作、网络请求、磁盘读写等),从而避免程序在执行这些操作时被阻塞,能够在等待结果的过程中继续执行其他任务。通过异步编程,可以实现高效的并发处理,尤其是在处理大量 I/O 密集型任务时,比传统的同步阻塞模型更具性能优势。

必备概念#

循环列表#

async & 协程对象#

import asyncio


async def fun():
    print("你好")


# loop = asyncio.get_event_loop()
# loop.run_until_complete(fun())
asyncio.run(fun())  # python3.7

async:用于定义协程函数
协程对象:执行协程函数()得到协程对象

注意

  • 协程函数()只是返回协程对象,内部代码不会执行。如果想要运行协程函数内部代码,必须要讲协程对象交给事件循环来处理。
  • asyncio.run()需要python3.7及以上

await(必须放在异步函数中)#

await + 可等待对象(协程对象、Future、Task对象)

在 Python 的异步编程中,await 关键字用于在异步函数中暂停当前函数的执行,等待一个异步操作完成。

协程对象#

Task对象#

白话:在事件循环中添加多个任务的。
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。除了使用asyncio.create_task()函数以外,还可以用低层级的loop.create_task()asyncio.ensure_future()函数。不建议手动实例化Task对象。
注意:asyncio.create_task()函数在Python3.7中被加入。在Python3.7之前,可以改用低层级的asyncio.ensure_future()函数。

示例1

import asyncio


async def fun():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"


async def main():
    print("main开始")

    # 创建Task对象,将当前执行fun函数任务添加到事件循环。
    task1 = asyncio.create_task(fun())
    task2 = asyncio.create_task(fun())

    print("main结束")

    # 当执行某协程遇到IO操作时,会自动化切换执行其他任务。
    # 此处的await是等待相对应的协程全都执行完毕并获取结果
    ret1 = await task1
    ret2 = await task2
    print(ret1, ret2)


if __name__ == '__main__':
    asyncio.run(main())


"""
运行结果:
main开始
main结束
1
1
2
2
返回值 返回值
"""

示例2

import asyncio


async def fun():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"


async def main():
    print("main开始")

    # 创建Task对象列表
    task_list = [
        asyncio.create_task(fun(), name='n1'),
        asyncio.create_task(fun(), name='n2'),
    ]

    print("main结束")

    done, pending = await asyncio.wait(task_list, timeout=None)
    print(done)


if __name__ == '__main__':
    asyncio.run(main())


"""
运行结果:
1
1
2
2
{<Task finished name='n2' ...>, <Task finished name='n1' ...}
"""

示例3

import asyncio


async def fun():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"


if __name__ == '__main__':
    task_list = [
        fun(),
        fun(),
    ]

    done, pending = asyncio.run(asyncio.wait(task_list))
    print(done)


"""
运行结果:
1
1
2
2
{<Task finished name='Task-3' ...>, <Task finished name='Task-2' ...}
"""

asyncio.Future对象#

Task继承Future,Task对象内部await结果的处理基于Future对象来的。

示例1

import asyncio


async def main():
    # 获取当前事件循环
    loop = asyncio.get_running_loop()

    # 创建一个任务(Future对象),这个任务什么都不干。
    fut = loop.create_future()

    # 等待任务最终结果(Future对象),没有结果则会一直等下去。
    await fut


asyncio.run(main())

示例2

import asyncio


async def set_after(fut):
    await asyncio.sleep(2)
    fut.set_result("666")


async def main():
    # 获取当前事件循环
    loop = asyncio.get_running_loop()

    # 创建一个任务(Future对象),没绑定任何行为,则这个任务永远不知道什么时候结束。
    # 该任务并没有加入循环列表中
    fut = loop.create_future()

    # 创建一个任务(Task对象),绑定了set_after函数,函数内部在2s之后,会给fut赋值。
    # 即手动设置future任务的最终结果,那么fut就可以结束了。
    await loop.create_task(set_after(fut))

    # 等待Future对象获取最终结果,否则一直等下去
    data = await fut

    print(data)


asyncio.run(main())

另一个future对象(与asyncio.Future对象没关系)

image

image

image

异步迭代器#

在 Python 中,异步迭代器是一种可以在异步上下文中进行迭代的对象。它允许你以异步的方式遍历一系列值,这在处理异步数据源(如异步生成的数据或从异步数据库查询中获取的数据)时非常有用。

image

异步上下文管理器#

image

uvloop#

image

异步编程增强性能原因#

异步编程能够增强性能主要有以下几个原因:

一、充分利用等待时间

  1. 避免阻塞:在同步编程中,当一个任务进行 I/O 操作(如读取文件、网络请求等)时,程序会一直阻塞在这个操作上,等待其完成,在此期间 CPU 处于空闲状态,无法执行其他任务。而在异步编程中,当一个任务发起一个异步 I/O 操作后,它不会等待这个操作完成,而是立即返回继续执行其他任务。这样,CPU 可以充分利用这段等待时间去执行其他有用的工作,而不是被闲置。
  2. 并发执行:异步编程允许同时发起多个异步操作,这些操作可以在后台并发执行。例如,可以同时发起多个网络请求,而不需要等待一个请求完成后再发起下一个。这样可以大大提高程序的吞吐量和响应速度。

二、优化资源利用

  1. 减少线程开销:在传统的多线程同步编程中,每个线程都需要占用一定的系统资源,如内存和 CPU 时间片。当并发任务数量较多时,线程的创建和切换会带来较大的开销。而异步编程通常可以在一个或少量的线程上实现高并发,避免了大量线程带来的开销。
  2. 高效的事件循环:异步编程通常基于事件循环机制,事件循环可以高效地管理和调度异步任务。它能够快速地响应异步事件,并将控制权交给相应的任务处理函数,从而提高系统的整体效率。

三、更好的响应性

  1. 实时响应:对于需要对用户输入或外部事件做出快速响应的应用程序,异步编程可以确保即使在执行耗时任务时,程序也能及时响应用户操作或外部事件。例如,在一个图形用户界面应用程序中,异步编程可以确保界面在进行后台数据加载时仍然保持响应,不会出现卡顿现象。
  2. 可扩展性:异步编程使得程序更容易扩展和处理大量的并发请求。随着系统负载的增加,可以通过增加异步任务的数量或优化事件循环的调度策略来提高系统的性能,而不需要大量增加线程数量或硬件资源。

综上所述,异步编程通过充分利用等待时间、优化资源利用和提高响应性等方式,能够显著增强程序的性能,特别是在处理大量并发 I/O 操作或需要实时响应的场景下。

总结#

最大的意义:通过一个线程利用其IO等待时间去做一些其他事情。

作者:cloud-2-jane

出处:https://www.cnblogs.com/cloud-2-jane/articles/18577799

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   一只大学生  阅读(4)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示