发出异步 HTTP 请求并继续执行循环

Make an async HTTP request and continue executing the loop

我有一个简单的 python 函数,伪代码如下:

while True:

    # 1 - CPU Intensive calculations(Synchronous)
    
    
    # 2 - Take the result from the synchronous calculation and POST it to a server

while 循环 运行 永远存在,并在循环的前半部分进行 CPU 密集计算。所有这些都是 运行 同步进行的,没关系。 我想做的是通过使 POST 请求异步来节省一些时间。 while 循环需要永远 运行,但是我希望异步发出请求,以便循环可以继续下一次迭代,而无需等待请求解决。

想知道在不使用任何额外的情况下使用 asyncio 实现此目的的最佳方法是什么 threads/greenlets/processes

编辑


在这里发布问题之前,我尝试过这种方法:

async def example_function():
    # Synchronous CPU Intensive calculations

    client = httpx.AsyncClient()
    # Make a call to the REST API
    await client.post()


async def main():
    while True:
        await asyncio.gather(example_function(), example_function())


if __name__ == "__main__":
    asyncio.run(main())

我完全不熟悉 python 的异步编程。我尝试了 gather 方法,但是我的实现方法的缺陷是 example_function() 的第二次迭代不会异步生成 POST 请求。我知道 asyncio.gather() 基本上为传递给它的每个函数安排了一个任务,我有一个任务在等待,它继续执行下一个任务。但是,我需要 运行 example_function() 永远循环,而不仅仅是 n

Would like to know what is the best way to achieve this with asyncio without using any extra threads/greenlets/processes

如果你的代码是同步的,你将需要使用一些形式的多线程,但你可以通过asyncio为那个目的。例如,如果您 运行 通过 loop.run_in_executor() 同步代码,事件循环将在计算 运行ning 期间保持旋转,并且将处理置于后台的任务。这允许您在后台使用 asyncio.create_task() 到 运行 循环的第二部分,或者更准确地说,与事件循环的其余部分并行使用。

def calculations(arg1):
    # ... synchronous code here

async def post_result(result, session):
    async with session.post('http://httpbin.org/post',
                            data={'key1': result}) as resp:
        resp.raise_for_status()

async def main():
    loop = asyncio.get_event_loop()

    with aiohttp.ClientSession() as session:
        while True:
            # run the sync code off-thread so the event loop
            # continues running, but wait for it to finish
            result = await loop.run_in_executor(None, calculations, arg1)

            # don't await the task, let it run in the background
            asyncio.create_task(post_result(result, session))

if __name__ == '__main__':
    asyncio.run(main())