python-3.x 如何同时运行两个异步方法?

kuhbmx9i  于 2022-12-15  发布在  Python
关注(0)|答案(1)|浏览(210)

我很惭愧地承认,我已经使用python的asyncio很长一段时间了,但并没有真正理解它是如何工作的,现在我陷入了困境。在伪代码中,我当前的程序是这样的:

async def api_function1(parameters):
    result = await asyncio.gather(*[some_other_thing(p) for p in parameters])

async def api_function2(parameters):
    result = await asyncio.gather(*[some_other_thing2(p) for p in parameters])    

def a(initial_parameters): 
    output = []
    data = asyncio.run(api_function1(initial_parameters))
    output.append(data)
    while True: 
        data = asyncio.run(api_function1(get_parameters_from_data(data)))
        output.append(data)
        if some _condition is True:
            break
    return output 

def b(initial_parameters): 
    output = []
    data = asyncio.run(api_function2(initial_parameters))
    output.append(data)
    while True: 
        data = asyncio.run(api_function2(get_parameters_from_data(data)))
        output.append(data)
        if some condition is True:
            break
    return output

a()和B()从两个不同的REST API端点获取数据,每个端点都有自己的速率限制和细微差别。我希望同时运行a()和b()。
构造程序使a()和b()同时运行的最好/最简单的方法是什么?
我尝试让a()和B()都是异步方法,并尝试同时等待它们,例如

async a(initial_parameters):
    ...

async b(initial_parameters):
    ...

A = await a(initial_parameters)
B =  await b(initial_parameters)

但它不起作用,所以根据文档,我猜我可能需要手动获取event_loop并将其作为参数传递给a()和b(),a()和b()将其传递给api_function2()和api_function2(),然后在两个任务都完成时手动关闭它,但不确定我是否走对了路或如何操作。
如果你有一个更好的设计模式,也可以打开它

kknvjkwl

kknvjkwl1#

没有理由不能嵌套对asyncio. gather的调用,如果想同时运行a()和B(),必须使它们都成为协程,并且不能asyncio.run在其中任何一个中使用www.example.com()。因为这是一个阻塞调用-它在参数完成之前不会返回。您需要替换a()和b()中对asyncio.run()的所有调用用wait表达式。你会得到如下的结果:

async def api_function1(parameters):
    return await asyncio.gather(*[some_other_thing(p) for p in parameters])

async def api_function2(parameters):
    return await asyncio.gather(*[some_other_thing2(p) for p in parameters])    

async def a(initial_parameters): 
    output = []
    data = await api_function1(initial_parameters)
    output.append(data)
    while True: 
        data = await api_function1(get_parameters_from_data(data))
        output.append(data)
        if some _condition is True:
            break
    return output 

async def b(initial_parameters): 
    output = []
    data = await api_function2(initial_parameters)
    output.append(data)
    while True: 
        data = await api_function2(get_parameters_from_data(data))
        output.append(data)
        if some condition is True:
            break
    return output

async def main():
    a_data, b_data = asyncio.gather(a(initial_parameters), b(initial_parameters))
    
async def main():
    task_a = asyncio.create_task(a(initial_parameters))
    task_b = asyncio.create_task(b(initial_parameters))
    a_data = await task_a
    b_data = await task_b
    
asyncio.run(main())

这仍然是伪代码。
我给出了两种可能的编写main的方法(),一个使用asyncio.gather,另一个使用对asyncio.create_task的两次调用。这两个版本都创建了两个同时运行的任务,但后一个版本不需要像gather那样将所有任务收集在一个位置并同时启动它们。如果gather像这里一样满足您的要求,它更方便。
最后,调用asyncio.run启动程序。文档建议每个程序只调用一次asyncio.run
这两个API函数应该返回一些东西,而不是设置一个局部变量。
在asyncio中,关键的概念是任务。任务相互协作以提供同步执行。Asyncio.gather实际上在引擎盖下创建任务,即使你通常传递给它一个协程列表。这就是它并行运行事情的方式。

相关问题