Python 异步编程与 asyncio

目录

一、什么是异步编程?

二、Python 中的 asyncio 简介

核心概念

三、如何使用 asyncio

1. 简单的异步函数

3. 异步网络请求示例

四、asyncio 的优势

1. 更好的 I/O 并发性能

2. 避免阻塞

3. 资源使用效率高

五、异步编程的挑战

六、总结


在 Python 中,除了多线程和多进程,异步编程是另一种处理并发任务的强大工具。异步编程特别适合处理 I/O 密集型任务,如网络请求、数据库操作等。asyncio 是 Python 内置的异步 I/O 框架,提供了基于协程的编程模型,允许我们编写高效、非阻塞的异步代码。

我们在上篇文章详细介绍了多进程和多线程的并发模式  那么本文将介绍上文结尾提到的异步编程的基本概念、asyncio 的使用方式,以及如何在实际项目中应用异步编程来提高程序性能。

一、什么是异步编程?

异步编程是一种并发编程模型,它允许程序在等待某些 I/O 操作(例如网络请求、文件读取等)时,不阻塞整个程序,而是让程序继续执行其他任务,等到 I/O 操作完成后再处理结果。与传统的同步编程相比,异步编程可以显著提高程序的并发性能,特别是在处理大量 I/O 请求时。

在 Python 中,异步编程主要通过 协程(coroutine) 实现。协程是一种比线程更轻量的并发单元,基于事件循环来调度任务。

二、Python 中的 asyncio 简介

asyncio 是 Python 提供的异步 I/O 模块,专为处理大量 I/O 操作而设计。asyncio提供了一套异步函数和任务的工具,可以允许我们高效地执行并发操作。

核心概念
  • 事件循环(Event Loop)asyncio 使用事件循环来调度和执行协程。事件循环不断地检查是否有可执行的任务,并按顺序执行它们。
  • 协程(Coroutine):用 async def 定义的函数是协程,它是异步编程的基本单元。协程的执行会被挂起,直到遇到 await,等待异步操作完成。
  • 任务(Task):协程是懒执行的,需要通过 asyncio.create_taskawait 来启动协程并创建任务,任务会被事件循环调度执行。

三、如何使用 asyncio

1. 简单的异步函数

首先,创建一个最基本的异步函数。使用 async def 关键字定义协程,并使用 await 来等待其他异步函数的执行。

import asyncio

async def say_hello():
    print("Hello")
    await asyncio.sleep(1)
    print("World!")

# 启动事件循环
asyncio.run(say_hello())

输出结果为:

Hello
(等待 1 秒)
World!

在这个例子中,say_hello 是一个异步函数,await asyncio.sleep(1) 会暂停协程的执行 1 秒,允许事件循环在此期间处理其他任务。

import asyncio

async def worker(n):
    print(f"Worker {n} starting")
    await asyncio.sleep(2)
    print(f"Worker {n} finished")

async def main():
    tasks = []
    for i in range(5):
        task = asyncio.create_task(worker(i))
        tasks.append(task)

    await asyncio.gather(*tasks)

# 启动事件循环
asyncio.run(main())

输出结果为:

Worker 0 starting
Worker 1 starting
Worker 2 starting
Worker 3 starting
Worker 4 starting
(等待 2 秒)
Worker 0 finished
Worker 1 finished
Worker 2 finished
Worker 3 finished
Worker 4 finished

在这个例子中,我们通过 asyncio.create_task 创建了 5 个异步任务,并使用 asyncio.gather 来并发执行它们。所有任务会同时启动,并在 2 秒后全部完成。

3. 异步网络请求示例

asyncio 通常用于处理大量 I/O 操作,例如网络请求。以下示例展示了如何使用 aiohttp(一个基于 asyncio 的 HTTP 客户端库)进行异步 HTTP 请求。

首先,安装 aiohttp

pip install aiohttp

然后,编写以下代码:

import asyncio
import aiohttp

async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

async def main():
    urls = [
        "https://example.com",
        "https://httpbin.org/get",
        "https://www.python.org"
    ]
    
    tasks = [fetch(url) for url in urls]
    results = await asyncio.gather(*tasks)
    
    for result in results:
        print(result[:100])  # 打印前 100 个字符

# 启动事件循环
asyncio.run(main())

四、asyncio 的优势

1. 更好的 I/O 并发性能

asyncio 能够显著提升 I/O 密集型任务的并发性能,尤其是在处理大量网络请求或文件读写时。相比传统的多线程或多进程,asyncio 的协程更加轻量,不需要创建额外的线程或进程,减少了上下文切换的开销。

2. 避免阻塞

异步编程的最大优势在于它不会像同步代码那样阻塞程序。即使某个任务需要等待 I/O 操作完成,事件循环也会继续执行其他任务,提高整体的执行效率。

3. 资源使用效率高

asyncio 使用事件循环调度任务,协程之间通过 await 暂停与恢复,节省了大量的系统资源(例如线程和进程)。在 I/O 密集型任务中,这种方式相比多线程和多进程更加高效。

五、异步编程的挑战

尽管异步编程有很多优势,但它的学习曲线较高,代码的可读性和调试难度也有所增加。我们需要适应 asyncawait 的语法,并掌握事件循环的工作原理。另外,asyncio 更适合处理 I/O 密集型任务,而在 CPU 密集型任务中,它的优势不如多进程。

六、总结

asyncio 是 Python 中处理异步编程的强大工具,特别适合 I/O 密集型任务,如网络请求、数据库查询、文件读写等。通过事件循环和协程,asyncio 可以并发执行多个任务而不阻塞程序。相比传统的多线程和多进程,asyncio 具有更轻量的特点,并且在 I/O 并发场景中能提供显著的性能提升。

在实际开发中,如果你需要处理大量 I/O 操作,异步编程可能是最佳选择;而对于 CPU 密集型任务,仍然可以考虑使用多进程来充分利用多核 CPU 的优势。

  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值