Python 异步协程asyncio详解

Python 异步协程asyncio详解

Python 异步协程asyncio详解

简介

在传统的同步编程中,我们调用一个函数后,只有等它返回了结果,我们才能继续往下执行。而在异步编程中,我们不需要等待这个函数返回结果,可以立即执行下一个函数。

Python 提供了 asyncio 模块来支持异步编程,其中的 asyncawait 关键字可以方便地定义异步函数和协程。本文将详细介绍 asyncio 的使用方法和一些实例。

asyncio 模块基本概念

在开始学习 asyncio 之前,我们先了解一些异步编程相关的基本概念。

协程(Coroutine)

协程是一种特殊的函数,它可以被中断和恢复,并且可以多次执行。在 asyncio 中,协程使用 async def 来定义。

任务(Task)

任务是对协程的封装,它可以通过 asyncio.create_task() 函数来创建。任务的运行可以通过 await 关键字进行中断,也可以通过 await asyncio.gather() 等待多个任务同时完成。

事件循环(Event Loop)

事件循环是异步编程的核心,它负责调度协程和任务的执行。在 asyncio 中,事件循环可以通过 asyncio.get_event_loop() 获取,并通过 loop.run_until_complete() 来启动。

异步函数(async function)

异步函数是一种特殊的函数,可以使用 await 关键字来中断其执行。

使用 asyncio

下面是一个简单的例子,展示了如何使用 asyncio 实现异步编程。

import asyncio

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

loop = asyncio.get_event_loop()
loop.run_until_complete(hello())

运行以上代码,输出如下:

Hello
World

在上面的例子中,我们定义了一个名为 hello 的异步函数,其中使用 await asyncio.sleep(1) 来模拟一个耗时的操作。然后我们创建了一个事件循环,并通过 loop.run_until_complete() 来运行 hello 函数。输出结果显示 HelloWorld 几乎是同时打印的,说明 asyncio 实现了真正的异步执行。

异步IO操作

异步编程的主要目标是处理 IO 操作。在传统的同步编程中,当我们进行一个 IO 操作时,程序会被阻塞,只有等到 IO 操作完成后才能继续执行。而异步编程可以在等待 IO 操作时继续执行其他任务,从而提高程序的并发性能。

使用 asyncio 可以方便地实现异步 IO 操作。下面是一个例子,展示了如何使用 asyncio 进行文件读写操作。

import asyncio

async def read_file(file):
    with open(file, 'r') as f:
        return await f.read()

async def write_file(file, text):
    with open(file, 'w') as f:
        await f.write(text)

async def main():
    text = await read_file('input.txt')
    await write_file('output.txt', text.upper())

asyncio.run(main())

以上代码中,我们定义了两个异步函数 read_filewrite_file,分别用于异步读取文件和异步写入文件。然后我们定义了一个 main 函数,它使用 await 关键字来等待读取文件操作完成后再进行写入文件操作。最后我们使用 asyncio.run() 来运行 main 函数。

并发执行多个任务

在异步编程中,经常需要同时执行多个任务,以提高程序的并发性能。asyncio 提供了多个函数来实现并发执行多个任务的功能。

asyncio.gather()

asyncio.gather() 函数可以同时运行多个任务,并等待它们全部完成。下面是一个例子:

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():
    await asyncio.gather(task1(), task2())

asyncio.run(main())

以上代码中,我们定义了两个异步任务 task1task2,它们分别等待 1 秒和 2 秒。然后在 main 函数中使用 asyncio.gather() 同时运行这两个任务,并等待它们全部完成。输出结果如下:

Task 1 completed
Task 2 completed

asyncio.wait()

asyncio.wait() 函数可以同时运行多个任务,并等待其中一个任务完成。下面是一个例子:

import asyncio

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

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

async def main():
    done, pending = await asyncio.wait([task1(), task2()], return_when=asyncio.FIRST_COMPLETED)
    for task in done:
        print(task.result())

asyncio.run(main())

以上代码中,我们定义了两个异步任务 task1task2,它们分别返回字符串表示任务完成。然后在 main 函数中使用 asyncio.wait() 同时运行这两个任务,并等待其中一个任务完成。输出结果如下:

Task 1 completed

asyncio.as_completed()

asyncio.as_completed() 函数可以同时运行多个任务,并按照完成的顺序返回一个迭代器。下面是一个例子:

import asyncio

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

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

async def main():
    tasks = [task1(), task2()]
    for task in asyncio.as_completed(tasks):
        print(await task)

asyncio.run(main())

以上代码中,我们定义了两个异步任务 task1task2,它们分别返回字符串表示任务完成。然后在 main 函数中使用 asyncio.as_completed() 同时运行这两个任务,并按照完成的顺序返回一个迭代器。输出结果如下:

Task 1 completed
Task 2 completed

异常处理

在异步编程中,异常的处理比同步编程更加复杂。asyncio 提供了一些机制来方便地处理异常。

使用 try-except

我们可以使用 try-except 块来捕获异步任务中发生的异常。下面是一个例子:

import asyncio

async def task():
    await asyncio.sleep(1)
    raise ValueError("Error in task")

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

asyncio.run(main())

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程