How do I yield to another request when using gunicorn with asyncio?

烈酒焚心 提交于 2021-01-26 19:42:32

问题


I'm trying to use the gaiohttp worker in Gunicorn with a Django app I'm developing with the following command:

gunicorn -k gaiohttp -b localhost:8080 myproject.wsgi

My ultimate goal is to be able to process requests concurrently - i.e. have 1 gunicorn worker process multiple requests concurrently. There are I/O bound operations which makes these requests slow.

I know an event loop is already running when I'm processing a request:

class MyView(View):

    def get(self, request):
        loop = asyncio.get_event_loop()
        loop.is_running() # True
        ...

Questions:

  1. How can I perform an operation such as yield from asyncio.sleep(10) within my view code?

    class MyView(View):
    
        def get(self, request):
            # Raises AssertionError: yield from wasn't used with future
            yield from asyncio.sleep(10)
    
  2. I can add tasks to the event loop, however they don't block while processing the request

    @asyncio.coroutine
    def simulate_work():
        yield from asyncio.sleep(10)
    
    class MyView(View):
    
        def get(self, request):
            # This runs simulate_work(), however, it doesn't block 
            # the response is returned before simulate_work() is finished
            loop = asyncio.get_event_loop()
            task = loop.create_task(simulate_work())
    
  3. I try to use futures, but the event loop is already running

    @asyncio.coroutine
    def simulate_work(future):
        yield from asyncio.sleep(10)
        future.set_result('Done!')
    
    class MyView(View):
    
        def get(self, request):
            future = asyncio.Future()
            asyncio.async(simulate_work(future))
            loop = asyncio.get_event_loop()
            # Raises RuntimeError: Event loop is running.
            loop.run_until_complete(future)
            print(future.result())
    

Clearly there's something I'm not understanding about asyncio or gaiohttp.

How can I have asyncio.sleep(10) block for the current requests, but not block gunicorn from processing other requests?


回答1:


Sorry, you cannot call coroutines from your wsgi application -- WSGI is synchronous protocol, as well as frameworks built on top of it (Django, Flask, Pyramid).

I've implemented gaiohttp worker but it's second class citizen in asyncio world. If you really need asynchronous HTTP server please try aiohttp.web.



来源:https://stackoverflow.com/questions/28222429/how-do-i-yield-to-another-request-when-using-gunicorn-with-asyncio

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!