当前位置: 首页 > 面试题库 >

如何使用python的asyncio模块正确创建和运行并发任务?

山越
2023-03-14
问题内容

我正在尝试Task使用Python
3的相对较新的asyncio模块正确理解和实现两个同时运行的对象

简而言之,asyncio似乎旨在处理Task事件循环中的异步过程和并发执行。它促进了await(应用于异步函数中)作为无回调方式等待和使用结果的使用,而不会阻塞事件循环。(期货和回调仍然是可行的选择。)

它还提供了asyncio.Task()该类,该类Future
是用于包装协程的专门子类。最好通过使用该asyncio.ensure_future()方法来调用。异步任务的预期用途是允许独立运行的任务与同一事件循环中的其他任务“同时”运行。我的理解是Tasks连接到事件循环,然后该循环自动继续驱动await语句之间的协程。

我喜欢无需使用任何一个Executor类就可以使用并发Task的想法,但是我并没有在实现上做过多的阐述。

这是我目前正在做的事情:

import asyncio

print('running async test')

async def say_boo():
    i = 0
    while True:
        await asyncio.sleep(0)
        print('...boo {0}'.format(i))
        i += 1

async def say_baa():
    i = 0
    while True:
        await asyncio.sleep(0)
        print('...baa {0}'.format(i))
        i += 1

# wrap in Task object
# -> automatically attaches to event loop and executes
boo = asyncio.ensure_future(say_boo())
baa = asyncio.ensure_future(say_baa())

loop = asyncio.get_event_loop()
loop.run_forever()

在尝试同时运行两个循环任务的情况下,我注意到,除非该任务具有内部await表达式,否则它将卡在while循环中,从而有效地阻止了其他任务的运行(就像正常while循环一样)。但是,一旦任务必须(a)等待,它们似乎可以并发运行而没有问题。

因此,这些await语句似乎为事件循环提供了一个立足点,可在任务之间来回切换,从而带来并发效果。

内部输出示例await

running async test
...boo 0
...baa 0
...boo 1
...baa 1
...boo 2
...baa 2

不带 内部输出的示例await

...boo 0
...boo 1
...boo 2
...boo 3
...boo 4

此实现是否通过了并发循环Task的“适当”示例asyncio

唯一可行的方法是Task提供一个阻塞点(await表达式)以便事件循环处理多个任务是否正确?


问题答案:

是的,事件循环中运行的任何协程将阻止其他协程和任务运行,除非它

  1. 使用yield fromawait(如果使用Python 3.5+)调用另一个协程。
  2. 退货。

这是因为asyncio是单线程的。事件循环运行的唯一方法是没有其他协程正在积极执行。使用yield from/await暂时暂停协程,使事件循环有工作的机会。

您的示例代码很好,但是在很多情况下,您可能不希望开始时没有在事件循环内运行不执行异步I /
O的长时间运行的代码。在这些情况下,通常更适合asyncio.loop.run_in_executor在后台线程或进程中运行代码。ProcessPoolExecutor如果您的任务是CPU限制的,则是更好的选择;如果您ThreadPoolExecutor需要执行一些asyncio不友好的I
/ O ,则将使用它。

例如,您的两个循环完全受CPU限制,并且不共享任何状态,因此,最好的性能来自ProcessPoolExecutor于跨CPU并行运行每个循环:

import asyncio
from concurrent.futures import ProcessPoolExecutor

print('running async test')

def say_boo():
    i = 0
    while True:
        print('...boo {0}'.format(i))
        i += 1


def say_baa():
    i = 0
    while True:
        print('...baa {0}'.format(i))
        i += 1

if __name__ == "__main__":
    executor = ProcessPoolExecutor(2)
    loop = asyncio.get_event_loop()
    boo = asyncio.create_task(loop.run_in_executor(executor, say_boo))
    baa = asyncio.create_task(loop.run_in_executor(executor, say_baa))

    loop.run_forever()


 类似资料:
  • 我试图正确理解和实现两个并发运行的任务对象使用Python 3相对较新的异步模块。 简而言之,asyncio似乎被设计用于处理异步进程和事件循环上的并发执行。它提倡使用(应用于异步函数)作为无回调的方式来等待和使用结果,而不阻塞事件循环。(期货和回调仍然是可行的选择。) 它还提供了

  • 问题内容: 我需要创建一个可以同时从Web套接字和管道接收消息的软件,并在另一个通道上发送消息(它从套接字接收消息,创建一个新线程并发送到管道。以与从管道接收消息相同的方式,创建一个新线程并发送到套接字。 我在使用多线程时遇到问题,在程序启动时,我必须启动方法,但只能启动。我尝试删除所有代码并仅保留,但仅输入的。 该程序由子进程调用,父进程通过连接到stdout和stdin的管道与之通信。 更新:

  • 问题内容: 假设我们有很多链接可供下载,并且每个链接可能花费不同的时间来下载。而且我只能使用最多3个连接进行下载。现在,我想确保使用asyncio有效地做到这一点。 这是我要实现的目标:在任何时间点,请尝试确保至少运行3个下载。 数字代表下载链接,连字符代表等待下载。 这是我现在正在使用的代码 输出是预期的: 但是这是我的问题: 目前,我只是在等待9秒钟以使主要功能保持运行状态,直到下载完成。在退

  • 4.4.1 模块的创建和使用 在 Python 语言中,模块对应于 Python 程序文件,即每个 Python 程序文件就是一个模块。 模块是 Python 程序的最高层结构单元,用于组织程序的代码和数据,以便能被同一程 序的其他模块甚至被其他程序重用。一个模块可以导入其他模块,导入后就可以使用其他模 块中定义的函数、类等对象。 用模块作为程序的结构单元,至少有三个作用: (1)代码重用:将代码

  • 这就是我所拥有的理想构建脚本: 我确实想手动执行任务“unzip_natives_os”。但它似乎只在配置阶段起作用。当我用这个设置进行测试运行时,它会给我一个错误:“java.lang.UnsatifiedLinkError”,但是如果我在dependencies块中将配置从“NativeSos”更改为“RuntimeOnly”,它就能正常工作。我是否必须显式地创建这个“ApplicationD

  • 问题内容: 我正在尝试使用Bokeh而不是matplotlib复制此问题中显示的HeatMap。我不能完全正确。现有的示例并没有帮助我了解我在做什么错。我卑微的尝试 给 请注意,尽管标题相似,但这并不能回答我的问题。这不是相同的错误,我正在使用Bokeh 0.12.3 问题答案: 更改数据的生成以按元素重复,并且它应该是正确的: 因此,适用于我的代码如下: