Search code examples
python-3.xasynchronousrequestpython-asynciononblocking

Python 3.7 Non-Blocking Request?


I'd like to do a non-blocking http request in Python 3.7. What I'm trying to do is described well in this SO post, but it doesn't yet have an accepted answer.

Here's my code so far:

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

What is the correct way to do an Ajax-style non-blocking http request in Python?


Solution

  • Asyncio makes it easy to make a non-blocking request if your program runs in asyncio. For example:

    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')
    

    But this requires that the "caller" be async as well. In your case you want the whole asyncio event loop to run in the background, so that. This can be achieved by running it in a separate thread, e.g.:

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

    However, in that case you're not getting anything by using asyncio. Since you're using threads anyway, you could as well call a sync function such as requests.get() to begin with.