前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python协程、异步IO与asyncio

Python协程、异步IO与asyncio

原创
作者头像
五分钟学SRE
发布2023-11-17 21:51:46
3550
发布2023-11-17 21:51:46
举报
文章被收录于专栏:五分钟学SRE五分钟学SRE

Python,作为一门流行的编程语言,不仅具备清晰简洁的语法和强大的生态系统,还在异步编程领域拥有丰富而灵活的工具,其中包括协程、异步IO以及asyncio库。本文将深入探讨这些概念的本质,解释它们的原理,并通过实际示例演示如何应用它们,帮助我们更好地理解和利用Python的异步编程能力。

概念介绍

Python协程

  • 协程是一种轻量级的线程,用于非阻塞异步编程。
  • 通过async和await关键字定义,使得函数可以在执行中暂停和恢复。
  • 协程可以用于处理高并发的I/O密集型任务,而无需使用多线程或多进程的复杂性。
  • 通常与异步IO一起使用,以实现高效的非阻塞IO操作。

异步IO

  • 异步IO是一种编程模型,用于处理非阻塞IO操作,以提高程序的并发性能。
  • 它允许一个程序同时处理多个IO操作,而不需要等待每个IO操作完成。
  • 在Python中,异步IO通常与协程一起使用,以实现高效的非阻塞IO编程。

asyncio

  • asyncio是Python标准库中的异步IO库,用于编写基于协程的异步程序。
  • 它提供了事件循环(event loop),用于调度和执行协程任务。
  • asyncio包含了许多工具和函数,用于处理异步IO操作,例如网络通信、文件IO等。
  • asyncio是Python中异步编程的核心库,可以用于构建高性能的异步应用程序,如Web服务器、聊天应用程序等。

协程(Coroutines)

????协程是一种轻量级的线程,它允许函数在执行过程中暂停并恢复。与常规函数不同,协程具有多个入口点,可以在函数内部的任何位置暂停和继续执行。Python的协程通过async和await关键字来定义和管理。

基本概念

在Python中,协程的基本概念如下:

  • async def:通过在函数定义前添加async关键字,可以将普通函数变成协程函数。协程函数可以在执行过程中暂停。
  • await:await关键字用于在协程中等待另一个协程或异步操作完成。当执行到await语句时,协程将暂停,直到等待的操作完成。

示例

下面是一个简单的协程示例,演示了如何使用协程来实现异步任务:

代码语言:javascript
复制
import asyncio
async def hello(arg):
    print("Hello : ",arg)
    if arg == "SRE 1":
        await asyncio.sleep(2)
    else:
        await asyncio.sleep(1)
    print("World : ",arg)
    print("bingo!!")
async def main():
    await asyncio.gather(hello("SRE 1"), hello("SRE 2"), hello("SRE 3"))
asyncio.run(main())

运行可以看到日志

代码语言:javascript
复制
Hello :  SRE 1
Hello :  SRE 2
Hello :  SRE 3
World :  SRE 2
bingo!!
World :  SRE 3
bingo!!
World :  SRE 1
bingo!!

????在这个示例中,hello函数是一个协程,通过await asyncio.sleep(1)来模拟一个耗时的操作。main函数使用await asyncio.gather()来同时运行多个协程。

异步IO(Asynchronous IO)

异步IO是一种编程模型,用于处理非阻塞的IO操作。它使程序能够在执行IO操作时继续执行其他任务,而不必等待IO操作完成。

基本概念

异步IO的核心概念包括:

  • 非阻塞IO:异步IO允许执行非阻塞的IO操作,这意味着程序在等待IO完成时不会被阻塞。
  • 事件循环:异步IO通常使用事件循环来管理协程和异步任务的调度。事件循环负责将协程放入等待IO的队列,并在IO完成时恢复它们的执行。

示例

以下示例演示了如何使用异步IO进行文件读取操作:

代码语言:javascript
复制
import asyncio
# 定义一个异步函数,模拟一个非阻塞的IO操作
async def non_blocking_io_operation(arg):
    print("开始非阻塞IO操作")
    if arg == "task1":
        await asyncio.sleep(2)  # 模拟IO操作,这里使用await来模拟异步操作
    else:
        await asyncio.sleep(5)
    print(f"完成调用:{arg} 的非阻塞IO操作")
# 创建一个事件循环
async def main():
    # 将非阻塞IO操作放入事件循环中
    task1 = asyncio.create_task(non_blocking_io_operation("task1"))
    task2 = asyncio.create_task(non_blocking_io_operation("task2"))
    # 等待所有任务完成
    await task1
    print("完成task1 IO执行!")
    await task2
    print("完成task2 IO执行!")
# 启动事件循环
if __name__ == "__main__":
    asyncio.run(main())

执行输出日志

代码语言:javascript
复制
开始非阻塞IO操作
开始非阻塞IO操作
完成调用:task1 的非阻塞IO操作
完成task1 IO执行!
完成调用:task2 的非阻塞IO操作
完成task2 IO执行!复制

asyncio库

asyncio 是异步 I/O 的缩写。它是一个 Python 库,允许我们使用异步编程模型运行代码。这让我们可以同时处理多个 I/O 操作,同时仍然允许我们的应用程序保持响应能力。

Python 3.4 引入了 asyncio 库,Python 3.5 生成了 async 和await 关键字以方便地使用它。这些新增功能允许所谓的异步编程。

基本概念

asyncio库的基本概念包括:

  • 事件循环(Event Loop):事件循环是异步程序的核心,负责调度协程和处理异步任务的完成。
  • asyncio.run():这个函数用于运行主协程,它在Python 3.7及更高版本中可用。
  • asyncio.create_task():用于创建并调度协程任务。

简单示例

以下示例展示了如何使用asyncio库来并发执行多个协程任务:

代码语言:javascript
复制
import asyncio
async def task1():
    print("into task1 ....")
    await asyncio.sleep(2)
    print("Task 1 completed")
async def task2():
    print("into task2 ...")
    await asyncio.sleep(1)
    print("Task 2 completed")
async def main():
    task1_handle = asyncio.create_task(task1())
    task2_handle = asyncio.create_task(task2())
    await task1_handle
    await task2_handle
asyncio.run(main())
代码语言:javascript
复制
在这个示例中,我们使用asyncio.create_task()创建了两个协程任务,并且可以并发执行它们。await关键字用于等待任务完成。

异步事件循环

????事件循环是 asyncio 应用程序的核心,负责处理所有正在运行的任务。事件循环支持多任务处理。当一个函数被挂起时,控制权返回到循环,然后循环找到另一个函数来启动或恢复。

image.png
image.png

使用事件循环的语法

代码语言:javascript
复制
loop = asyncio.get_event_loop()
loop.run_until_complete(my_coroutine())
loop.close()

示例

代码语言:javascript
复制
import asyncio
import time
async def cor1():
    print("cor 1 started")
    for i in range(5):
        await asyncio.sleep(1.5)
        print("cor1", i)
async def cor2():
    print("cor 2 started")
    for i in range(8):
        await asyncio.sleep(1)
        print("cor2", i)
loop = asyncio.get_event_loop()
cors = asyncio.wait([cor1(), cor2()])
loop.run_until_complete(cors)复制

运行可以得到输出

代码语言:javascript
复制
cor 2 started
cor 1 started
cor2 0
cor1 0
cor2 1
cor1 1
cor2 2
cor2 3
cor1 2
cor2 4
cor1 3
cor2 5
cor2 6
cor1 4
cor2 7

任务

任务用于同时调度协程。我们使用函数 create_task() 创建一个任务。使用此函数将协程包装到任务中。

示例

代码语言:javascript
复制
import asyncio
import time
async def main():
  # 使用 asyncio.create_task() 方法创建任务
    task1 = asyncio.create_task(foo('task 1 run'))
    task2 = asyncio.create_task(foo('task 2 run'))
    print(f"started at {time.strftime('%X')}")
    # 等待所有任务执行完成
    await task1
    await task2
    print(f"finished at {time.strftime('%X')}")
async def foo(text):
    print(text)
    await asyncio.sleep(1)
asyncio.run(main())

得到输出

代码语言:javascript
复制
started at 17:35:47
task 1 run
task 2 run
finished at 17:35:48

同时运行任务

为了执行并发执行,我们使用函数 Gather 如下。可等待的 asyncio.gather(*aws, return_exceptions=False)

该函数采用任意数量的可等待项(协程、任务等)作为参数。

示例

代码语言:javascript
复制
import asyncio
# 定义一个异步函数,用于打印文本并在每次打印后等待一段时间
async def printing(task, text):
    while True:
        print(task, text)
        try:
            await asyncio.sleep(0.50)  # 等待0.50秒,模拟异步操作
        except asyncio.CancelledError:
            break  # 如果收到取消请求,跳出循环结束任务
async def main():
    try:
        # 使用 asyncio.wait_for 设置一个超时时间为 3 秒,同时并发运行三个打印任务
        await asyncio.wait_for(
            asyncio.gather(
                printing("A", "task 1"),
                printing("B", "task 2"),
                printing("C", "task 3")
            ), 3  # 超时时间设置为 3 秒
        )
    except asyncio.TimeoutError:
        print("Time over")  # 如果超时,打印 "Time over" 提示
asyncio.run(main())

得到输出

代码语言:javascript
复制
A task 1
B task 2
C task 3
A task 1
B task 2
C task 3
A task 1
B task 2
C task 3
A task 1
B task 2
C task 3
A task 1
B task 2
C task 3
A task 1
B task 2
C task 3
Time over
_GatheringFuture exception was never retrieved
future: <_GatheringFuture finished exception=CancelledError()>
concurrent.futures._base.CancelledError

异步编程提高了应用程序性能和响应能力。Python 提供了支持异步编程的不同库。Asyncio允许我们使用 async/await 语法编写并发代码。Asyncio 由协程、任务、流、子进程、异常等高级 API 和事件循环、Futures、传输和协议等低级 API 组成。

可以查看原文:

https://mp.weixin.qq.com/s?__biz=MzA5NTgwNzY1NA==&mid=2247484074&idx=1&sn=82db976658d234dc16350a85c2709f23&chksm=90b8f363a7cf7a75c1315d099d573fc15075dfd5ef8637797cf57a7e3ae6d9250cb97e67a2ce&token=211557010&lang=zh_CN#rd

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念介绍
  • 协程(Coroutines)
    • 基本概念
      • 示例
      • 异步IO(Asynchronous IO)
        • 基本概念
          • 示例
          • asyncio库
            • 基本概念
              • 简单示例
                • 异步事件循环
                  • 使用事件循环的语法
                    • 任务
                      • 同时运行任务
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
                      http://www.vxiaotou.com