前言

Python 异步编程是一种编程方式,用于处理可以并发执行的任务,以提高程序的效率和性能。异步编程允许在一个线程中执行多个任务,通过在某些任务等待 I/O 操作(如文件读写、网络请求等)完成时切换到其他任务,从而更有效地利用 CPU 资源。

一、异步编程的概念

1-1、异步编程

异步编程: 是一种编程范式,允许程序在等待某些操作完成时不阻塞线程或进程,继续执行其他任务。这种方式使得资源利用更高效,特别是在 I/O 密集型操作(如网络请求、文件读写等)中表现尤为显著。

1-2、同步 vs 异步

同步 vs 异步

  • 同步:任务按顺序执行,一个任务未完成时,后续任务必须等待。这种方式直观但效率较低,尤其在处理 I/O 操作时。
  • 异步:任务可以并发执行,一个任务在等待时,其他任务仍可继续进行。这样可以提高资源利用率和程序的响应速度。

1-3、阻塞 vs 非阻塞

阻塞 vs 非阻塞

  • 阻塞操作:会使得程序等待操作完成,期间无法执行其他任务。例如,读取文件时,程序会等待文件完全读取后再继续执行。
  • 非阻塞操作:操作会立即返回,程序可以继续执行其他任务。例如,发起一个网络请求后,程序可以继续执行其他任务,等待请求完成时再处理结果。

1-4、并发 vs 并行

并发 vs 并行

  • 并发:在同一时间段内处理多个任务,不一定是同时进行,但看起来像是同时进行。
  • 并行:在同一时刻同时处理多个任务,通常需要多核处理器支持。

二、Python 异步编程的主要模块

2-1、asyncio

asyncio 是 Python 标准库中的一个模块,专门用于编写并发代码。它提供了事件循环、协程、任务和各种 I/O 操作的异步支持。

  • 事件循环(Event Loop):asyncio 的核心组件,负责调度和管理协程的执行。事件循环不断运行,检查并执行准备好的任务。
  • 协程(Coroutine):使用 async def 定义的函数,可以在等待某个操作完成时挂起并允许其他协程运行。
  • 任务(Task):由事件循环管理的协程,通过 asyncio.create_task() 创建,可以并发执行。
  • 未来对象(Future):表示一个异步操作的结果,通常不直接使用,而是通过任务和协程间接使用。

2-2、async 和 await 关键字

async 和 await 关键字

  • async:用于定义协程函数。协程函数是可以在执行过程中挂起并恢复的函数。
  • await:用于暂停协程的执行,等待某个异步操作完成,然后继续执行。await 后面可以跟随一个返回 awaitable 对象(如协程、任务或未来对象)的表达式。注意: 异步函数需要使用 await 关键字进行调用, 如果不使用await,调用异步函数只会返回一个协程对象,函数内部的异步操作不会实际执行。

2-3、 aiohttp

aiohttp 是一个用于构建异步 HTTP 客户端和服务器的库。它基于 asyncio 实现,允许在异步环境中进行高效的 HTTP 通信。

  • HTTP 客户端:使用 aiohttp 可以发起异步 HTTP 请求,不阻塞主线程,处理大量并发请求时性能优越。
  • HTTP 服务器:aiohttp 提供了构建异步 HTTP 服务器的能力,适用于高并发环境。

三、案例分析

3-0、安装

pip install asyncio

3-1、基本案例

概述: 使用await挂起协程的执行,即模拟的IO操作,直到被等待的任务完成。asyncio.run() 用于启动一个事件循环并运行协程。

import asyncio

async def fetch_data():
    print("Start fetching data...")
    await asyncio.sleep(2)  # 模拟 I/O 操作,实际应用中可以是网络请求或文件读写
    print("Data fetched.")
    return "Data"

async def main():
    print("Main started")
    result = await fetch_data()  # 等待 fetch_data 完成
    print("Result:", result)
    print("Main finished")

# 获取事件循环并运行 main 协程
asyncio.run(main())

输出:
在这里插入图片描述

3-2、并发执行多个任务

概述: 可以使用 asyncio.gather() 或 asyncio.create_task() 来并发执行多个任务

两个任务并发

import asyncio

async def task1():
    await asyncio.sleep(1)
    print("Task 1 completed")

async def task2():
    await asyncio.sleep(2)
    print("Task 2 completed")

async def main():
    tasks = [task1(), task2()]
    await asyncio.gather(*tasks)  # 并发执行所有任务

asyncio.run(main())

输出:

在这里插入图片描述

多任务并发:

import time
import asyncio

# 定义异步函数
async def hello():
    await asyncio.sleep(1)
    print('Hello World:%s' % time.time())

async def main():
    tasks = [hello() for i in range(5)]
    await asyncio.gather(*tasks)

if __name__ == '__main__':
	# 自动创建一个事件循环,运行传递给它的协程,并在运行结束后关闭事件循环。
	# 这种方法适合简单的脚本和程序,因为它隐藏了事件循环的管理细节。
    asyncio.run(main())

多任务并发:等价于上边的函数,但是更底层

import time
import asyncio

# 定义异步函数
async def hello():
    await asyncio.sleep(1)
    print('Hello World:%s' % time.time())

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    tasks = [hello() for i in range(5)]
    # 运行事件循环,直到传递的任务完成。
    # 我们可以把一些函数(通过 async 定义的函数,称为协程)注册到事件循环上,当满足事件发生的条件时,调用相应的协程函数。
    # asyncio.wait 和 asyncio.gather的功能类似,但可以更灵活地处理任务完成的顺序。
    loop.run_until_complete(asyncio.wait(tasks))

多任务并发总结:

  • 第二段代码使用 asyncio.run(),这是一个高层次的 API,简化了事件循环的创建、运行和关闭过程。
  • 第三段代码手动获取和管理事件循环,更低层次,可以提供更大的灵活性。

3-3、异常处理

概述: 异步函数中的异常处理与同步代码类似,但需要在协程中使用 try、except 块


import asyncio

async def faulty_task():
    await asyncio.sleep(1)
    raise ValueError("An error occurred!")

async def main():
    try:
        await faulty_task()
    except ValueError as e:
        print("Caught an exception:", e)

asyncio.run(main())

输出:
在这里插入图片描述

3-4、与队列结合

概述: 异步编程还支持与异步生成器、队列、锁等高级特性结合使用,以实现更复杂的并发逻辑。

import asyncio

async def producer(queue):
    for i in range(5):
        await asyncio.sleep(1)
        await queue.put(i)
        print(f"Produced {i}")

async def consumer(queue):
    while True:
        item = await queue.get()
        if item is None:
            break
        print(f"Consumed {item}")
        queue.task_done()

async def main():
    queue = asyncio.Queue()
    await asyncio.gather(producer(queue), consumer(queue))
    await queue.join()

asyncio.run(main())

输出:
在这里插入图片描述


参考文章:
【测试开发】python系列教程:asyncio模块
理解python异步编程与简单实现asyncio

MetaGPT异步编程基础

总结

🤣沉迷于DNF手游无法自拔。

Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐