暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Python 异步编程: asyncio模块

yangyidba 2024-09-04
109

一 协程的定义与Python 的实现

1.1 协程是什么

协程 是一种轻量级的并发单元,它允许在等待异步操作(如 I/O 操作)时挂起,从而让出控制权给事件循环,以便执行其他任务。简单来说可以认为协程是线程里不同的函数,这些函数之间可以相互快速切换。协程的主要特点包括:

  1. 非阻塞:协程在等待异步操作时不会阻塞事件循环,从而实现非阻塞的并发执行。
  2. 协作式多任务:协程通过 await 表达式主动让出控制权,实现协作式多任务处理。
  3. 易于编写:使用 async/await 语法,协程的编写和理解都相对简单直观。

在 Python 中,asyncio
是一个用于编写并发代码的库,它使用 async
/await
语法。async
定义了一个协程,而 await
用于等待异步操作完成。协程是一种轻量级的线程,它允许在等待异步操作完成时挂起,从而让出控制权给其他协程。

asyncio 函数的源代码地址:https://github.com/python/cpython/tree/3.8/Lib/asyncio

1.2  特点

  • 非阻塞:协程是非阻塞的,它们在等待异步操作时不会阻塞整个程序的执行。
  • 轻量级:相比传统的线程,协程不需要操作系统级别的上下文切换,其开销更小。
  • 易于编写asyncio
    使用 async/await 语法,协程的编写和理解都相对简单直观。
  • 单线程:尽管协程可以并发执行,但它们通常在单个线程内运行,由事件循环来调度。

1.3 适用场景

  1. I/O 密集型任务:如网络请求、文件读写等,这些操作通常需要等待外部资源,协程可以在等待时释放控制权。
  2. 高并发:需要同时处理大量并发连接或任务,但每个任务的执行时间较短。
  3. 异步 API:与异步 API 交互,如异步数据库访问、异步 HTTP 客户端等。

1.4 限制

  1. 需要编译器提供语义支持,比如C# yield return语法糖。

  2. 只能在这个生成器内挂起此协程,无法在嵌套函数中挂起此协程。

  3. 关键字有一定传染性,异步代码必须都有对应的关键字。

二 asyncio 协程相关函数的使用

创建协程

使用 async def
定义一个协程函数:

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

运行协程

使用 asyncio.run()
来运行协程:

asyncio.run(my_coroutine())

等待协程

使用 await
等待协程完成:

async def main():
    print("Start")
    await my_coroutine()
    print("Finished")

asyncio.run(main())

并发运行多个协程

使用 asyncio.gather()
并发运行多个协程:

async def coroutine1():
    print("Coroutine 1 started")
    await asyncio.sleep(2)
    print("Coroutine 1 finished")

async def coroutine2():
    print("Coroutine 2 started")
    await asyncio.sleep(1)
    print("Coroutine 2 finished")

async def main():
    await asyncio.gather(coroutine1(), coroutine2())

asyncio.run(main())

三 使用场景代码示例

3.1 网络请求

使用 aiohttp
库进行异步 HTTP 请求:

import aiohttp
import asyncio

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

async def main():
    async with aiohttp.ClientSession() as session:
        html = await fetch(session, 'http://python.org')
        print(html)

asyncio.run(main())

3.2 模拟处理请求

假设我们模拟一个简单的Web服务器,该服务器能够同时处理多个客户端的HTTP GET请求,每个请求需要从数据库或其他服务获取数据,这是一个典型的I/O密集型任务。

import asyncio

async def handle_client(client_id, delay):
    print(f"客户端{client_id} 连接,开始处理请求...")
    await asyncio.sleep(delay)  # 模拟数据处理或I/O操作
    print(f"客户端{client_id} 请求处理完毕")

async def main():
    clients = [handle_client(i, i % 3 + 1for i in range(16)]  # 创建不同延时的客户端请求
    await asyncio.gather(*clients)  # 同时处理所有客户端请求

asyncio.run(main())

四 小结

asyncIO 及其协程模型为 Python 开发者提供一种高效处理并发I/O操作的方法。通过合理的运用  async/await 语法、事件循环以及任务管理,开发者便能够轻松构建高性能的异步应用程序。


文章转载自yangyidba,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论