首页 > 解决方案 > Python 3.7 非阻塞请求?

问题描述

我想在 Python 3.7 中做一个非阻塞的 http 请求。我正在尝试做的事情在这个 SO post中有很好的描述,但它还没有一个公认的答案。

到目前为止,这是我的代码:

import asyncio
from aiohttp import ClientSession

[.....]

async def call_endpoint_async(endpoint, data):
    async with ClientSession() as session, session.post(url=endpoint, data=data) as result:
        response = await result.read()
        print(response)
        return response

class CreateTestScores(APIView):
    permission_classes = (IsAuthenticated,)

    def post(self, request):
        [.....]
        asyncio.run(call_endpoint_async(url, data))
        print('cp #1') # <== `async.io` BLOCKS -- PRINT STATEMENT DOESN'T RUN UNTIL `asyncio.run` RETURNS

在 Python 中执行 Ajax 风格的非阻塞 http 请求的正确方法是什么?

标签: python-3.xasynchronousrequestpython-asynciononblocking

解决方案


如果您的程序在 asyncio 中运行,Asyncio可以很容易地发出非阻塞请求。例如:

async def doit():
    task = asyncio.create_task(call_endpoint_async(url, data))
    print('cp #1')
    await asyncio.sleep(1)
    print('is it done?', task.done())
    await task
    print('now it is done')

但这要求“调用者”也必须是异步的。在您的情况下,您希望整个 asyncio 事件循环在后台运行,这样。这可以通过在单独的线程中运行来实现,例如:

pool = concurrent.futures.ThreadPoolExecutor()

# ...
    def post(self, request):
        fut = pool.submit(asyncio.run, call_endpoint_async(url, data))
        print('cp #1')

但是,在这种情况下,您不会通过使用 asyncio 得到任何东西。由于无论如何您都在使用线程,因此您也可以调用一个同步函数,例如requests.get()开头。


推荐阅读