Python异步编程 – asyncio和await

Python异步编程 – asyncio和await

asyncio模块。asyncio模块具有出色的功能,允许我们编写更高效的Python异步应用程序。我们将探讨如何在Python中管理异步事件循环。在深入探讨这个主题之前,让我们了解什么是异步编程。

什么是异步编程

在同步编程中,方法是按顺序执行一个任务。如果一个函数依赖于另一个函数的输出,它必须等待该函数执行完毕。程序实质上会在函数执行完毕之前停止。这意味着一次只能执行一个程序。

这会减慢程序的运行,因为它被强制停下来等待某件事完成。系统中有许多处理器,所以做其他任务而不是理想的是浪费资源。

为了克服这个问题,引入了异步编程概念。它的行为不同;它也一次只执行一个程序。但是系统可能不会等待完成执行才继续下一步。

这意味着处理器在程序尚未完成且仍在其他地方运行时不会空闲。

在本教程中,我们将解释为什么需要这种类型的编程。

什么是asyncio – 异步I/O

asyncio是一个Python库,用于使用async/wait运行并发代码。它是Python异步框架的基础,提供了连接库、网络和Web服务器、数据库分布式任务队列、高性能等功能。

此模块提供的框架围绕事件循环工作,并负责处理I/O和系统事件等事项。

协程和任务

asyncio是一个用于使用async/wait运行并发代码的Python库。它是Python异步框架的基础,提供了连接库、网络、Web服务器、数据库分布式任务队列、高性能等功能。

此模块提供的框架围绕事件循环工作,并负责处理I/O和系统事件等事项。

示例1

import asyncio
async def main():
    print ("Waiting 5 seconds. ")
    for _ in range(5):
        await asyncio.sleep(1)
        print ("Hello")
    print ("Finished waiting.")
asyncio.run(main())

输出:

Waiting 5 seconds. 
Hello
Hello
Hello
Hello
Hello
Finished waiting.

解释 –

在上面的代码中 –

  • 我们导入了asyncio模块,以便可以使用Python的 异步 功能。
  • 然后创建一个 primary() 函数,并在前面加上async关键字。这将允许程序以异步的方式运行任务。
  • 我们使用for循环并调用 sleep() 方法,强制程序等待1秒。
  • 程序在一秒钟后打印“Hello”。
  • 程序应该有一个 .run() 函数和一个 .main() 函数。

我们还可以安排绑定协程并帮助它们运行的任务或对象。让我们理解以下示例。

示例2

import asyncio
import time

async def execute(delay, value):
    await asyncio.sleep(delay)
    print(value)

async def main():
    print(f"started at {time.strftime('%X')}")

    await execute(1, 'hello')
    await execute(2, 'world')

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

输出:

started at 11:11:54
hello
world
finished at 11:11:57

说明 –

在上面的代码中,

  • 我们导入了asyncio和time模块。
  • 然后我们定义了 execute() 函数,它带有延迟时间和值作为参数。它使用 sleep() 方法打印延迟时间。
  • main() 函数中,我们传入了两个参数:第一个是延迟时间,第二个是要打印的值。
  • 程序开始执行,并打印出确切的执行时间,打印“hello”,然后等待两秒钟并打印“world”,然后停止。

现在,让我们对上面的代码进行一些更改,并查看结果。

示例3 创建任务

async def execute(delay, value):
    await asyncio.sleep(delay)
    print(value)

async def main():
    # Using asyncio.create_task() method to run coroutines concurrently as asyncio
    task1 = asyncio.create_task(
        execute(1, 'hello'))

    task2 = asyncio.create_task(
        execute(2, 'world'))

    print(f"started at {time.strftime('%X')}")

    # Wait until both tasks are completed (should take
    # around 2 seconds.)
    await task1
    await task2

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

输出:

started at 15:43:30
hello
world
finished at 15:43:32

我们可以看到,它比之前的程序快了1秒。 create.task() 方法将在事件循环中运行,并将其结果放在任务中。我们已经安排了这两个任务,并使用await返回了它们。

在Python中管理异步事件循环

Asyncio还用于管理异步事件循环。事件循环是一个运行异步函数和回调的对象。当我们想要执行协程时,当我们运行 asyncio.run() 方法时,事件将对于异步函数来说至关重要;事件循环对象会自动创建。为了实现更高级的服务器,我们需要对事件循环的底层访问。我们需要直接与事件循环的内部进行交互。

事件循环具有以下功能。

  • 它可以注册、执行和取消延迟调用(异步函数)。
  • 可以创建客户端和服务器传输进行通信。
  • 可以创建子进程和用于与另一个程序通信的传输。
  • 将函数调用委托给一个线程池。

让我们看下面的示例。

示例 –

import asyncio

async def speech_async():
    print('This is a asynchronicity!')

loop = asyncio.get_event_loop()
loop.run_until_complete(speech_async())
loop.close()

输出:

This is a asynchronicity!

事件循环通过获取 asyncio.get_event_loop() 来启动,安排和运行异步任务,并在运行完成后关闭事件循环。

在Python中使用流进行数据读写

asyncio模块提供了 stream ,用于执行高级网络I/O操作。它可以作为网络请求的服务器。它非常适合于长时间运行的网络操作,此时应用程序会阻塞并等待其他资源返回结果。

asyncio中有两个类 StreamReader和StreamWriter ,这些类用于在网络上进行高级读写。

要从网络中读取,我们需要使用 asyncio.open_connection() 打开网络连接。 StreamReaderStreamWriter 对象函数返回元组,我们将使用.read()和.write()方法对每个连接进行读写。

使用 asyncio.start_server() 方法从远程主机接收连接。此函数接受一个回调函数 client_connected_cb 作为参数。每当该函数接收到请求时,都会调用它。

Python中的同步任务

我们之前讨论过,异步程序运行独立,但有时我们希望彼此通信。asyncio模块为我们提供了队列和其他各种方法来建立任务之间的同步。

让我们了解以下实现方法。

  • 队列 – asyncio队列使得异步函数能够排队Python对象,以供其他异步函数消费。例如 – 工作负载在其行为上分布在函数之间。
  • 同步原语 – asyncio的特性锁、事件、条件和信号量的行为与传统的Python对应物相同。

在这里,始终要记住这些方法不是 线程安全 。这对于在同一事件循环中运行的异步任务来说并不是问题。但我们需要使用线程模块来在任务之间共享信息。

何时使用异步编程

在以下场景中,我们可以使用异步编程。

  • 当我们希望在较短时间内完成工作。
  • 延迟涉及等待I/O(磁盘或网络)操作,而不是计算。
  • 当许多I/O操作同时发生时。

asyncio模块允许我们并行执行多个任务,并有效地迭代它们,而不会阻塞应用程序的其他部分。

以下是一些与asyncio搭配使用效果良好的任务。

  • 网络爬虫。
  • 网络服务(Web服务器和框架)。
  • 并发数据库。

Asyncio中的一些重要函数

以下是在异步编程中使用的一些重要方法。

运行asyncio程序

  • asyncio.run(coro, *, debug = False) 这个函数用来阻塞执行 delay 秒。它暂停当前任务并允许另一个任务运行。延迟是一个参数,表示秒数。

示例

async def main():
    await asyncio.sleep(1)
    print('hello')
asyncio.run(main())

创建任务

  • create_task(coro, *, name=None) 此函数将协程包装为任务,并安排其执行。它返回任务对象。

示例

async def coro():
    ...

# In Python 3.7+
task = asyncio.create_task(coro())
...
task = asyncio.ensure_future(coro())

睡眠

  • sleep(delay, result = None, *, loop = None) – 此函数用于阻塞执行 delay 秒钟。它暂停当前任务,并允许其他任务运行。延迟是一个参数,表示秒数。

示例

import asyncio
async def main():
    for _ in range(3):
        await asyncio.sleep(1)
        print ("Hello")
asyncio.run(main())

等待超时

  • coroutine wait_for(aw, timeout, *, loop = None) – 这个函数用于等待aw(一个作为Task自动调度的协程) awaitable 在超时之后完成。

示例

async def myfunc():
    # Sleep for ten minutes
    await asyncio.sleep(600)
    print('hello!')

async def main():
    # Wait for at most 1 second
    try:
        await asyncio.wait_for(myfunc(), timeout=1.0)
    except asyncio.TimeoutError:
        print('timeout!')

asyncio.run(main())

结论

在本教程中,我们介绍了使用Python的asyncio模块进行异步编程的概念。asyncio使我们能够在使用上下文切换时对程序进行编程控制。这意味着我们可以处理许多与线程编程相关的复杂问题。

它是一种强大而有价值的工具,但仅适用于异步类型的编程。我们已经讨论了协程和任务以及它们的示例。我们还讨论了如何管理事件循环以及在Python中使用流读取和写入数据。它还包括一些基本的方法。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程